废话不多说,直接进入正题。
目录
一、Object类
1.介绍Object类
2.toString方法
3.equals方法
4.hashCode方法
二、内部类
1.静态内部类
2.实例内部类
3.匿名内部类
4.局部内部类
一、Object类
1.介绍Object类
(1)Object类就是所有类的父类/超类,也称为祖先类。也就是说所有的类都会默认继承于Object类,即使你没有定义继承关系
(2)Object类具有的方法
1)在本文中,我们重点介绍三个方法:toString()、equal()、hashCode()
2)因为Object类是所有类的父类,所以我们创造的任何类,都可以直接使用上面的方法,也可以重写上述的方法(当然,构造方法除外)
下面介绍三个常用的重写方法
2.toString方法
(1)不重写打印自定义类型对象时
可见,打印出来的是一堆乱码。
(2)了解打印方法的背后执行流程
这也就是为什么直接打印,会得出一些看不懂的数据。要想改变结果,就需要重写父类的toString()方法。
(3)重写方法
class Person {
public String name = "张三";
public int age = 10;
@Override
public String toString() {
return "名字:"+name+" 年龄:"+age;
}
}
public class Test1 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
打印结果:
当子类重写了toString方法后,最终打印时,调用的toString()方法也就是重写的方法。
(4)使用编译器生成
第一步:右键鼠标或者Alt + Lnsert,并且点击Generate…
第二步:点击toString()
第三步:勾选。当只有一个被选择的时候,按住ctrl再进行勾选即可
生成的结果展示:
小结:当我们想打印自定义类型中的数据,并且打印的结果并非目标值时,可以重新toString()方法。简易记忆法:System.out.println()方法最终调用的是toString()方法
3.equals方法
该方法用于比较两个对象是否相等(相同),但是不能比较两个对象的大小关系
3.1.介绍方法背景
(1)两个普通变量比较是否相等
结果是明显的,是我们所想要的。
这也是我们所想要的
(2)比较两个实例对象时
结果大失所望
(3)再比较自定义类型对象时
结果仍是大失所望,这里的原因是:复杂类型和引用类型不能使用==进行比较是否相等,因为==比较的是他们的地址是否相等,很显然,new出来的对象地址是不会相等的。但是前面简单的变量和字符串却可以,因为他们的地址一样。
(4)使用equals方法比较
啊?不是说equals方法是用来比较两个对象是否相同的吗?为什么结果还是不对?这就是下面想要介绍的了
3.2.查看equals方法执行过程
(1)方法背后调用
当我们以为equals方法底层很厉害的时候,点开却发现,底层也是使用==比较,难怪说比较的使用和预期不一样。
(2)这样设置的原因是编译器也不知道程序员想要比较的对象是什么。如果是复杂类型对象,像上面的Son,是比较名字是否相等呢?还是比较年龄是否相等呢?
3.3.重新equals方法
(1)自定义写
自定义的比较规则:先查看其中一个对象是否为null,再比较名字是否相同,最后比较年龄。如果三者全部一样,则可以认为是同一个人,也就是两个对象相同。
运行结果:结果就是预期,很正确
上述的几点解释:第一点:使用参数时,需要先向下转型,因为父类对象无法访问到子类对象的成员;第二点:不是说重新equals方法吗?怎么还调用equals方法比较?原因是当String类原码重写了equals方法,当String类型去调用时,可以正确的。
2)String类型重写equals方法
这样比较时,结果也是正常的
3)查看String类重写的equals方法
不用去理解重写是如何实现的,只需要记住,如果是String类型,可以直接调用equals方法。
(2)编译器生成
和上面生成toString()方法差不多
1)第一步
2)第二步
3)按照默认选项,一直next下去即可
4)结果
equals方法和hashCode()方法一起生成的,如果不需要再直接删除hashCode()方法即可
4.hashCode方法
这个方法的作用是比较两个对象在内存中存储的位置是否相同。比如两个对象内容一样,就可以认为是同一个对象,也就应该存放在同一块内存空间上面。
拿下面的例子举例
(1)未重写时
(2)重写后
本文的hashCode()方法就介绍这么多,后续在数据结构的哈希表中还有用处(hashCode的重点用法)
二、内部类
内部类介绍,通常的来说,就是在一个类的内部再定义一个类,作为外部类的一个成员。内部类的定义方式和之前介绍过的组合写法类似。
1.静态内部类
(1)语法格式
static class 类名 {}
(2)定义静态内部类
class Outer {
public int data1 = 1;
public int data2 = 2;
public static int data3 = 3;
//定义静态内部类
static class Inter {
public int data4 = 4;
public static int data5 = 5;
public void func() {
System.out.println("我是静态内部类的方法~");
}
public Inter() {
System.out.println("我是静态内部类的构造方法!");
}
}
public void func() {
System.out.println("我是外部类的方法~");
}
}
由此可见,静态内部类中也可以有自己的成员变量、成员方法和构造方法,而且方法名与变量名可以与外部类的名字相同。
(3)静态内部类的访问方式
时刻牢记,内部类也是属于外部类的一个成员。
实例化静态内部类对象:
访问成员和方法:
使用静态内部类的引用,是无法访问到外部类的任何成员的。
(4)在静态内部类中访问外部类
这样操作可以发现,在静态内部类中,可以直接访问外部内的静态成员,非静态不可以直接访问。
非静态成员则需要通过对象的引用来访问。同样,访问方法的方式和访问成员变量一样,这里不再过多介绍。
(5)静态内部类的优点和注意事项
优点:访问静态内部类对象不需要创造外部类对象,因为这样的优点,该内部类后续用的场景较多。
注意事项:
1)在静态内部类中只能访问外部类中的静态成员;如果需要访问,则需要先在内部类中创造外部类对象,使用对象的引用进行访问。
2)不使用外部类对象的引用访问 内部类和外部类名字相同的成员时(静态成员与方法),会优先访问静态内部类的
2.实例内部类
实例内部内的定义位置和静态内部类类似,但是定义的格式少了static关键字
(1)语法格式
class 类名 {}
(2)定义实例内部类
(3)定义实例内部类对象
像静态内部类的形式创造对象,结果是得到一场串的波浪号。很明显,创建实例内部类的对象并不能如此。
第一种:先创建外部类对象,再使用和实例静态内部类的方式去创建。究其原因是实例内部类是属于对象的,创造实例内部类时,就需要通过外部类对象的引用;而静态内部类不属于外部类对象,进而不用创造外部类对象
第二种方式:这样的写法就是第一种写法的合并,但是看起来比较丑陋
(4)使用内部类对象引用访问成员
实例内部类对象的引用也只能访问内部类中的成员,而不能访问外部类的成员
(5)内部类中访问外部类
在实例内部类中,可以访问外部类的所有成员方法和成员变量,包括静态的和非静态的。
(6)注意事项
3.匿名内部类
匿名内部类的应用场景大多数在对于接口的实现或者类的继承中,主要场景还是应用于对接口的实现中。
(1)匿名内部类简介
1)为什么匿名?因为该类实现了接口之后,是没有名字,不同于普通类实现接口(例如:普通类A是实现了接口B,此时A就是类名,是有名字的)
2)为什么是内部类?其实匿名内部类是局部内部类的一种,而且创造此类是必须要存在于一个类的方法中(一般是main函数中,而main函数要存在于一个类中)
3)使用目的:为了使用接口中的方法,本质上会发生向上转型
(2)匿名内部类定义
第一种创造方式:不使用引用(一次性对象)
interface Inter {
void func();
}
public class Test3 {
public static void main(String[] args) {
new Inter() {
@Override
public void func() {
System.out.println("我是重写的方法");
}
}.func();
}
}
匿名内部类实现了接口,并且重新了接口中的方法,然后使用该类调用了该接口中的方法
与普通类实现接口的对比:
两种方式的对比,很明显,第一种的方式很方便
第二种创建方式:给匿名内部类对象加上引用
这其实也是一种向上转型,并且发生了动态绑定。父类(接口)类型 引用了 子类(匿名内部类)对象,通过父类引用调用了子类重写的方法,最终会绑定到子类上。
与普通类的对比:
普通类可以使用两种类型的引用去接收该对象,原因是普通类的名字我是是可以知晓的,所以可以使用普通类的引用去接收,但是匿名内部类不行,他没有名字。
以上就是匿名内部类的定义和使用
(3)匿名内部类的注意事项
1)
2)匿名内部类中不能有构造方法
3)匿名内部类中不能有静态方法和变量
4.局部内部类
上面的匿名内部类就是局部内部类的代表,定义在方法中。局部内部类使用的场景非常的少。
(1)定义局部内部
(2)实例化局部内部类对象
由此可见,局部内部类是非常不方便的,典型的吃力不讨好,所以后续的使用场景非常的少。
以上就是本文的全部内容了