Java拾贝第四天——面向对象3
Java拾贝不建议作为0基础学习,都是本人想到什么写什么
多态性
面向对象最后一条也是最重要的特性。
多态性主要体现在两方面:
- 方法的重载与重写
- 对象的多态性
方法的重写
在Java拾贝第二天方法中提到了方法的重载。
现在基于继承Java提供了方法的重写。
即子类重写父类的方法:方法名,返回值类型,传参均相同就是重写
public class test3 {
public static void main(String[] args) {
Student s =new Student();//实例化子类时会优先实例化父类
s.say();
}
}
class Person {
public Person() {
System.out.println("父类的无参构造");//实例化任何类都会调用其无参构造方法
}
public void say() {
System.out.println("父类say方法");
}
}
class Student extends Person {
@Override
public void say() {
System.out.println("子类重写父类say方法");
}
}
/*
父类的无参构造
子类重写父类say方法
*/
对象的多态性
//实例化对象格式
对象 变量 = new 指向类型;
正常来说实例一个Person对象它指向的应该是Person类
Person p=new Person();
实例一个Student对象它指向的应该是Student类
Student s=new Student();
如果是实例化Person对象指向Student类呢?
public class test3 {
public static void main(String[] args) {
Person p=new Student();//Person指向Student
//它可以调用子类learn方法吗?
}
}
class Person {
public Person() {
System.out.println("父类的无参构造");
}
public void say() {
System.out.println("父类say方法");
}
}
class Student extends Person {
public Student() {
System.out.println("子类的无参构造");
@Override
public void say() {
System.out.println("子类say方法");
}
public void learn() {
System.out.println("子类learn方法");
}
}
但变量p只能使用父类Person类的方法,也就是说它没有子类的learn方法。
p.learn();//报错
因为Student继承自Person,所以它可以安全的赋值给变量p。这种安全的赋值称之为向上转型
//向上转型
Person p=new Student();
向上转型遵循的规则:
-
可以调用父类的所有属性和方法(但要遵循访问规则)
-
不能调用子类独立有的属性和方法(子类有但父类没有)
-
方法的运行效果具体看指向类型的实现(基于子类重写)
//运行下述代码就可以体现出第三点
public class test3 {
public static void main(String[] args) {
Person p = new Student();
p.say();
}
}
class Person {
public void say() {
System.out.println("父类say方法");
}
}
class Student extends Person {
@Override
public void say() {
System.out.println("子类say方法");
}
}
//子类say方法
基于向上转型方法的运行效果具体看指向类型的实现(基于子类重写)
若是子类没有重写父类的say方法,则运行结果是父类的具体实现。
基于子类重写!!!现补充另一条属性看对象。即 属性看对象,方法看指向
public class Test4 {
public static void main(String[] args) {
Sub sub = new Sub();
System.out.println(sub.i);
Base base = sub;
System.out.println(base.i);
}
}
class Base {
int i = 10;
}
class Sub extends Base {
int i = 20;
}
在Base类中,整型i默认为10。在Sub类中,整型i默认为20。
根据属性看对象得到上述代码运行结果为20 10。
//根据方法看指向。试想下述代码打印结果
public class Test4 {
public static void main(String[] args) {
Sub sub = new Sub();
System.out.println(sub.i);
sub.tell();
Base base = sub;
System.out.println(base.i);
base.tell();
}
}
class Base {
int i = 10;
public void tell() {
System.out.println(this.i);
}
}
class Sub extends Base {
int i = 20;
public void tell() {
System.out.println(this.i);
}
}
/*
20
20
10
20
*/
方法看指向
Sub sub = new Sub();//对象Sub指向Sub。
Base base = sub;//对象Base指向Sub。
至此向上转型:
-
可以调用父类的所有属性和方法(但要遵循访问规则)
-
不能调用子类特有的属性和方法(子类有但父类没有)
-
属性看对象,方法看指向
向下转型
向上转型后无法访问子类属性和方法该怎么办呢?为了解决这个问题就需要再向下转型。
和向上转型相反,如果把父类赋值给子类就是向下转型。
public static void main(String[] args) {
Student s =new Person();//这么转型是错误的!连编译都无法通过
Person p = new Student();//正确的向下转型
Student s = (Student) p;
}
//错误的向下转型
Student s =new Person();
一般来说子类都是父类的拓展,也就是子类属性和方法都比父类要多,这些多的功能不能凭空出现。所以会向下转型失败。
向下转型遵循的规则:
-
强转前父类指向的是强转后的对象本身
-
可以调用子类中的所有属性和方法
//第一条什么意思?
Person p = new Student();
Student s = (Student) p;//之前父类指向的是Student,现在强转为Student。
//强转后就等于 Student s=new Student();所以当然可以访问子类所有属性和方法
instanceof关键字
instanceof用于判断变量是否是指定类型或者其子类,构成一个布尔表达式
变量 instanceof 类名==布尔表达式
if(变量 instanceof 类名){};
栗子:
Person p = new Person();
System.out.println(p instanceof Person); // true
System.out.println(p instanceof Student); // false
System.out.println(p instanceof Object); // true 所有类都继承Object
Student s = new Student();
System.out.println(s instanceof Person); // true 子类属于父类
System.out.println(s instanceof Student); // true
Student n = null;
System.out.println(n instanceof Student); // false
System.out.println(n instanceof Object); // false
如果一个变量指向null,使用instanceof判断永远为false。