一.父类的引用指向子类对象
父类的引用指向子类对象用法:
1.调用属性时:只能调用父类属性,不能调用子类特有属性,且父类属性不能被子类重写;
2.调用方法时:只能调用父类方法,不能调用子类特有方法,但父类方法能被子类重写,父类方法被重写后被调用时,调用的是子类重写后的方法。
package com.wzn.extend;
/**
* @ClassName Father
* @Description TODO
* @Author wzn
* @Data 2023/2/8 9:23
**/
public class Father {
public String name = "爸爸";
public Integer age = 40;
void say(){
System.out.println("我是 " + name);
}
void activity(){
System.out.println(name + "正在下棋。。。");
}
void doFather(){
System.out.println(name + "正在钓鱼。。。");
}
}
package com.wzn.extend;
/**
* @ClassName Son
* @Description TODO
* @Author wzn
* @Data 2023/2/8 9:23
**/
public class Son extends Father{
private String name = "儿子";
private Integer age = 18;
private Integer testScore = 100;
void say(){
System.out.println("我是 " + name);
}
void activity(){
System.out.println(name + "正在打球。。。");
}
void sonDoFather(){
super.activity();
}
void sonDoHimself(){
this.activity();
}
}
package com.wzn.extend;
/**
* @Description 父类的引用指向子类对象总结:只能调用父类的方法和属性,不能调用子类特有的方法和属性,
* 父类方法可以被重写,父类属性不能被重写,父类方法被重写后被调用时,调用的是子类重写后的方法
* @Author wzn
* @Data 2023/2/8 9:39
**/
public class ExtendTest {
public static void main(String[] args) {
// //注意:直接“子类的引用指向父类对象“会报错:ClassCastException
// Son son = (Son) new Father();
// son.sonDoFather();
// //但是下面这种方法不会报错
// Father father = new Son();
// Son son = (Son) father;
// son.sonDoHimself();
//父类的引用指向子类对象用法:1.调用属性时:只能调用父类属性,不能调用子类特有属性,且父类属性不能被子类重写
// 2.调用方法时:只能调用父类方法,不能调用子类特有方法,但父类方法能被子类重写,
// 父类方法被重写后被调用时,调用的是子类重写后的方法
Father son = new Son();
son.say();
son.activity();
son.doFather();
// son.sonDoHimself()//调用子类特有方法会报错
// son.testScore();//调用子类特有属性会报错
System.out.println(son.age);
}
}
二、接口的引用指向实现类对象
接口的引用指向实现类对象,在开发中经常用到的,例如:
List list = new ArrayList();
Map map = new HashMap<>();
为什么要这么用呢?
这种写法其实Java多态的表现形式(一个接口类型的引用变量来引用实现接口的类的实例,当这个引用调用方法时,它会根据实际引用的类的实例来判断具体调用哪个方法)
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
为什么一般都使用 接口引用指向子类对象 ,而不用 实现类本身 引用呢?
问题就在于接口可以有多个实现类,如果现在你使用这个实现类接收,也许哪一天你需要换成其它的实现类呢?
这时你只要将new的实现类对象换成你想要的就行了, 其它地方的代码根本不需要改动。
注意事项:
没有在接口定义的方法(实现类增加的方法)是不可以被访问到的
在接口的实现类中该实现方法的类型和参数必须与接口中所定义的精确匹配。
换种说法:这其实是Java中多态的一种表现:
接口的实现类可以有很多个,如 LinkedList或者Vector等等,如果使用这种方式,List list = new ArrayList(); 以后不想用ArrayList了,直接改为你想用的实现类,如List list = new LinkedList(); 这样,虽然修改了实现类,但相关list调用方法的代码是不用修改的;如果是ArrayList list = new ArrayList();这种写法,那就有可能要修改非常多代码了,因为,原本list调用了ArrayList中的方法来实现某个功能,再修改实现类过后,list原本调用的方法在LinkedList中不存在,则还要修改对应调用的方法;因此:
两种方式其实都能实现同一种效果,只是接口的引用指向实现类对象这一方法,是用接口来规范了实现的方法,这样子写的话就很清楚的知道哪些方法有,哪些方法没有。
这就是一种设计规范,如果按照这种设计规范来写,就可以免去在修改实现的对象吼调用方法不存在的情况。
这样写的好处是便于程序代码的重构. 这就是面向接口编程的好处。
大佬的代码:
public class text {
public static void main(String[] arhs) {
Test a = new A();
Test t = new AB(a);
t.small();
}
}
interface Test{
void small();
}
class A implements Test{
@Override
public void small() {
System.out.println("我是A");
}
}
class B implements Test{
@Override
public void small() {
// TODO Auto-generated method stub
System.out.println("我是B");
}
}
class AB implements Test{
private Test test;
AB(Test test){
this.test = test;
}
//
@Override
public void small() {
// TODO Auto-generated method stub
test.small();
}
}
第二部分所参考大佬的文章(自己学习做笔记用,如有侵权,可联系删除):
https://blog.csdn.net/qq_39056520/article/details/114601463
https://blog.csdn.net/leng15183596537/article/details/89318188