JAVA中继承和多态中重名以及与JS的差异
JAVA与JS继承的实现逻辑(ES6之前)
继承的实现
JAVA继承是通过子类继承父类或实现接口,而在js中es6之前没有引入类的概念,而是通过原型链的方式来实现,构造方法、实例对象、原型对象三者在创建实例化对象之后形成三角关系,构造方法在定义之后就会有一个prototype原型对象属性,它指向该构造方法的原型对象,而在创建实例对象之后,实例对象又会有一个对象原型属性指向原型对象,并且在js中每个对象都有对象原型属性,原型对象也有一个对象原型属性指向上一级的原型对象、直到循环到Object*构造方法的原型对象,Object原型对象指向NULL结束,形成一条原型链,在实例对象使用其中的属性、方法的时候就会先找本原型对象身上有没有,如果没有就通过原型链向上查找,直到找到或找不到报错
图解
代码验证
```function fn(name) {
this.name = name
}
fn.prototype.sing = function() {
console.log('挂载到原型对象上的方法');
}
console.log(new fn('实例对象'))
输出结果可以明显看到__prop__的指向问题,而父级通过prototype挂载到构造函数上的方法,子级也可以用,从而解决了继承的问题,因为通过此方法定义的方法和变量都是静态成员,一般重名只需要依次向上找即可,而Java中通过继承和实现接口方式且会有成员变量,成员方法,局部变量重名的访问问题
没有多态的产生下的变量和方法重名问题
看一段代码实例
父类
public class Father {
String str="父类变量";
public void Method(){
System.out.println("父级函数");
}
public void setStr(String str) {
this.str = str;
}
public String getStr() {
return str;
}
}
子类
public class Son extends Father {
String str="子类变量";
public void Method(){
System.out.println("子类函数");
}
}
测试代码
public class ceshi {
public static void main(String[] args) {
Son son=new Son();
// 访问重名方法
son.Method();
// 直接方式访问重名变量
System.out.println(son.str);
// 间接方式访问重名变量
System.out.println(son.getStr());
}
}
此时由于没有多态的参与,直接访问只要看创建的实例对象是谁优先看此类里面的方法和变量即可,而间接访问由于是在父类中通过父类方法访问本类中的变量,也是优先使用本类的变量。
输出结果依次是子类方法 子类变量 父类变量
再看一段有多态产生时的例子
public class ceshi {
public static void main(String[] args) {
Father father=new Son();
// 访问重名方法
father.Method();
// 直接方式访问重名变量,此时便要优先看此时创建的对象属于什么类型的
// 而先去看这个类中的变量,没有就向上查找
System.out.println(father.str);
// 间接方式访问重名变量
System.out.println(father.getStr());
// 因为查找规则只会向父一级查找,不会向下查找,
// 如果非要访问子类变量, 必须向下转型才可以访问的到
Son son=(Son)father;
System.out.println(son.str);
}
}
此时第二个输出结果便成了父级变量,到这其实可以总结如果要以直接的方式访问成员变量,看它右边是什么类型的先去他的类中去找,如果访问成员方法,则需要看创建出来的实例对象是什么类型的,去他的类中去找,如果没有就向上查找
但是又尝试了一个特殊情况,如果通过此方法访问成员方法,别的都不变,在子类添加一个特有的成员方法,则会报错,这时候是编译时候无法找到此方法
具体原理是,一个类的方法定义会在java内存的方法区中,在编译期间会先去此类的方法区中去查找此方法的信息,但是在运行期间,会看堆中具体创建实例对象是什么类型,然后去方法去找对应类的方法,所以第二种情况报错原因就是编译没通过
本文地址:https://blog.csdn.net/q6301031/article/details/107074399