}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public Integer getId() {
return id;
}
@Override
public void setId(Integer id) {
this.id = id;
}
@Override
public String getNick() {
return nick;
}
@Override
public void setNick(String nick) {
this.nick = nick;
}
}
下面是父类
public class FatherTwo {
private Integer age;
private String name;
public String nick;
public Integer id;
public FatherTwo(Integer age, String name, String nick, Integer id) {
this.age = age;
this.name = name;
this.nick = nick;
this.id = id;
}
public FatherTwo() {
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNick() {
return nick;
}
public void setNick(String nick) {
this.nick = nick;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
}
调用方法测试一下方法与属性的优先级
public class TestExtend {
public static void main(String[] args) {
FatherTwo father = new SonTwo(1,“我是son”,1,“son”);
//方法是优先访问子类
System.out.println(father.getName());
System.out.println(father.getNick());
System.out.println(father.getId());
System.out.println(father.getAge());
//可以看到,会优先访问父类
System.out.println(father.id);
System.out.println(father.nick);
}
}
可以看到,没有子类的getOld方法,证明不可以调用父类没有的方法
阻止继承:final类和方法
给类加上final关键字,那么该类就不会被继承
给类中的特定方法加上final关键字,那么该方法就不可以被子类覆盖重写,final类中的所有方法自动地变成final方法
给属性加上final关键字,那么该属性必须在类构建实例的时候进行初始化,而且构建实例之后,这个属性不可以再被修改。
强制类型转化
前面已经学习过基本数据类型进行强制转换。
那么对于引用类型进行强制转化会怎样
将一个值赋值给变量时,编译器会去检查这样的行为是否承诺过多,如果将一个子类的引用赋值给父类的变量,那就没问题,如果将一个父类的变量引用赋值给子类,那么就承诺过多了(父类没有子类的完全功能,这个变量会缺少一部份功能),必须要进行强制转换。
应用类型的强制转化有如下规则
-
只能在继承层次内进行强制转换
-
在将父类强制转换成子类之前,应该使用instanceof进行检查
-
instanceof会查看是否能够成功地转化,如果可以,那就返回True,如果不行,就会返回false
我们仍然使用上面的父与子类来测试
public class TestExtend {
public static void main(String[] args) {
FatherTwo father = new SonTwo(1,“我是son”,1,“son”);
FatherTwo fatherTwo = new FatherTwo();
System.out.println(father instanceof SonTwo);
System.out.println(fatherTwo instanceof SonTwo);
}
}
可以看到,若父引用要可以强转成子变量,前提是这个父引用是子引用来的。
抽象类
继承产生了一种自上而下的层次结构,最上面的类更加具有一般性,可能更加抽象,而下层的类则在不断扩展
祖先类更有一般性,人们只将它作为派生其他类的基类,而不会去用来实例化想要得到的对象
抽象类的规则如下
-
抽象类可以有抽象方法,其他属性和方法都跟一般类一致(可以有public、protected和default这些修饰符)
-
抽象类不可以去实例化
-
抽象类也可以有自己的静态变量和静态方法,同样也可以直接使用抽象类进行调用
-
继承抽象类的所有对象也会继承静态方法和静态变量
-
如果抽象类被继承(只能被单继承)
-
如果是抽象类继承抽象类,可以不去实现父抽象类的抽象方法(但该抽象方法也会被子抽象类继承下来)
-
如果是一般类继承抽象类,必须去实现父抽象类的抽象方法
-
继承类无论是抽象类还是子类,都要在构造方法上调用super来构造父抽象类的实例
-
抽象类也要有自己的构造方法,只可以被子类使用super来调用(因为属性还是位于抽象类里面,需要对外提供构造方法来进行实例化),在单元测试上是不可以调用的,也就是不支持使用new去实例
权限修饰符
-
对外部完全可见——public
-
对本包和所有子类可见——protected
-
对本包可见——默认,不需要修饰符
-
仅仅对本类可见——private
一般来说,想要进行限制某个方法或者变量的话,使用protected。
Object:所有类的超类
Object类是Java中所有类的始祖,每个类都扩展了Object,但是并不需要去手动继承
如果没有明确指出超类,Object就被认为是这个类的超类
可能这里有人以为,那明确指出超类,不就没有Object当父类了吗?
其实并不是这样,因为Object始终位于架构的最上层,也就是最模糊最抽象的一层。
Object的equals方法可以看到Object实例的equals方法仅仅用于检测一个对象是否等于另外一个对象,即判断两个对象的引用地址是否相等
但Oject还提供了静态的比较方法
可以看到静态方法的equals不仅检测两个对象的引用地址是否相等,还会去检测一方是否为空,如果不为空,调用这一方的equals方法,前面提到过,如果Object a是由多态而来的,equals方法会优先调用子类的重写,所以这里不一定会调用object实例的equals
但一般这种机制不太够用,所以有时候类也要去重写equals方法。
public class Employee {
private String nickName;
private Integer employId;
public Employee(String nickName, Integer employId) {
this.nickName = nickName;
this.employId = employId;
}
public Employee() {
}
/idea自动生成的重写方法/
@Override
public boolean equals(Object o) {
//先判断是否是同一个引用
if (this == o) {return true;}
//判断比较的对象是否为空
//getClass方法是获取一个实例对象所属的类
//判断是不是通一个类
if (o == null || getClass() != o.getClass()){ return false;}
//强转成同一个类
Employee employee = (Employee) o;
//比较两个类的属性是否一样
//这里使用equals进行比较,注意这里的是静态方法equals
//也就是,如果属性如果为引用
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
类型,那么就会优先调用该引用类型重写的equals方法
return Objects.equals(nickName, employee.nickName) &&
Objects.equals(employId, employee.employId);
}
@Override
public int hashCode() {
return Objects.hash(nickName, employId);
}
}
可以看到,除了比较应用地址和类的类型之外,还会进行比较值,比较值的过程如下
-
调用Object的静态equals方法
-
会先比较属性的引用地址
-
然后比较其中一方是否为null,如果为null,就返回false
-
如果其中一方不为null,就会调用这一方的equals方法进行比较
-
继承关系会优先调用子类的equals方法
对于equals方法,可以看到只要class不一样,就会返回false,那么可能有一些人就想子类也能与父类进行比较
那么可以将类判断改成如下
//假设Employee是一个超类,Manager是一个子类
if(!(otherObject instanceof Employee)){return false;}
那么Employ实例的equals方法也可以跟Manager进行属性比较了
但强烈建议这种方式不太好
Java语言规范要求equals方法要有下面的特性
-
自反性:对于任何非空引用x,x.equals(x)应该返回true
-
对称性:对于任何引用x和y,x.equals(y)返回True时,那么y.equals(x)也要返回True
-
传递性:对于任何引用x、y和z,x.equals(z)返回True,y.equals(z)返回True,那么x.equals(y)也要返回True
假如使用了上面的判断
employee.equal(manager) //这是可以的,因为Manager instance Employee为true
manager.equal(employee) //这是不可以的,因为Employee instance Manager为false(承诺过多)
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)