面向对象 - 多态、static关键字、代码块
继续深入认识面向对象
狂神说Java BV12J41137hu
多态
多态讲的很好的一篇文章 Java多态性:Java什么是多态?
我建议直接看这一篇,我自己跟着狂神学,根本没听懂...
这里的案例上一篇 面向对象 - super、方法重写Override 已经写过了,这次写的简洁一些
Person.java
package oop.app.polymorphism;
public class Person {
}
Student.java
package oop.app.polymorphism;
public class Student extends Person{
}
这里看一下 子类(Student) 的继承树

我暂时理解为,
new Student(); 可以沿着继承树向上指向引用类型,也即可以由父类的引用指向子类
Application.java
package oop.app.polymorphism;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
Person s2 = new Student();
}
}
调用方法
Type 对象 = new Class(input);
在上式中,Type 指定 对象 的类型,对象可以调用自己的方法(很合理)
而通过多态来创建对象的时候,由于类型声明为父类,因而无法直接调用右侧子类的方法
但是IDEA提供了调用的策略
Person.java
package oop.app.polymorphism;
public class Person {
public void sayHi() {
System.out.println("Person: Hi");
}
}
Student.java
package oop.app.polymorphism;
public class Student extends Person{
public void sayHello() {
System.out.println("Student: Hello");
}
}
Application.java
package oop.app.polymorphism;
public class Application {
public static void main(String[] args) {
Student s1 = new Student(); // Student 类型 (sayHello 方法 ,继承的 sayHi 方法)
Person s2 = new Student(); // Person 类型 (sayHi 方法)
s1.sayHello();
s1.sayHi();
s2.sayHi();
// 当从Person类型调用Student类型的方法时
// s2.sayHello(); 报错 Cannot resolve method 'sayHello' in 'Person'
// 能执行哪些方法,主要看对象左边的类型,和右边的关系不大
// 我还是不建议子类写和父类同名的方法
}
}
Student: Hello
Person: Hi
Person: Hi
小总结:IDEA真的牛!
父类强制调用子类方法,需要做类型转化:
((Student) s2).sayHello(); // Person 转换为 Student 类型
注意事项
- 多态是方法的多态,属性没有多态;
- 父类和子类是有联系的,没有关系的类进行转换会抛出 类型转换异常
- ClassCastException
- 多态存在的条件:
- 存在继承关系
- 方法需要重写(不需要重写也就没有必要使用多态,我自己理解的)
- 父类的引用指向子类对象
Father f1 = new Son();
再次温习一下关键字
- static 修饰方法,属于类(这里指与类一起加载),它不属于实例
- final 常量
- private 私有方法,不能重写
总结
多态,即统一方法可以根据发送对象的不同而采用多种不同的行为方式;
一个对象的实际类型时确定的,但是可以指向对象的引用的类型有很多(沿引用树向上)
多态是方法的多态,属性没有用多态(复读一遍)
instanceof
直观理解,其判断一个对象是什么类型
instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。
用法
yourOBJ instanceof targetOBJ
没啥好讲的,暂时用不到这里,而且我觉得狂神讲的稀碎 - -||
static 关键字
静态变量
静态变量是跟随类的,可以使用类名访问(推荐);
静态变量在内存中只跟随类储存一个,无论这个类生成了多少个对象;
所有对象(实例)共享静态变量;
Student.java
package oop.app.mystatic;
public class Student {
protected static int numberOfStudent; // 静态变量
private int age; // 非静态变量
public static int getNumberOfStudent() {
return numberOfStudent;
}
}
Application.java
package oop.app.mystatic;
public class Application {
public static void main(String[] args) {
Student juniorMing = new Student();
Student juniorPing = new Student();
Student.numberOfStudent = 2;
System.out.println("juniorMing\t" + juniorMing.getNumberOfStudent());
System.out.println("juniorPing\t" + juniorPing.getNumberOfStudent());
System.out.println("Student\t" + Student.numberOfStudent);
//juniorMing 2
//juniorPing 2
//Student 2
}
}
静态方法
同静态变量
代码块
- 静态代码块
static {}跟随类,只执行一次; - 匿名代码块
{}跟随对象(实例),在构造器之前执行; - 存在继承情况时,记得构造器第一句是
super()即可
案例-单独类
Person.java
package oop.app.mystatic;
public class Person {
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造器方法");
}
public static void main(String[] args) {
Person person1 = new Person();
//静态代码块
//匿名代码块
//构造器方法
System.out.println("==================");
Person person2 = new Person();
//匿名代码块
//构造器方法
}
}
案例-继承类
Person.java
package oop.app.mystatic;
public class Person {
{
System.out.println("Person\t匿名代码块");
}
static {
System.out.println("Person\t静态代码块");
}
public Person() {
System.out.println("Person\t构造器方法");
}
}
Teacher.java
package oop.app.mystatic;
public class Teacher extends Person{
{
System.out.println("Teacher\t匿名代码块");
}
static {
System.out.println("Teacher\t静态代码块");
}
public Teacher() {
System.out.println("Teacher\t构造器方法");
}
}
Application.java
package oop.app.mystatic;
public class Application {
public static void main(String[] args) {
Teacher teacher = new Teacher();
}
}
STDOUT
Person 静态代码块
Teacher 静态代码块
Person 匿名代码块
Person 构造器方法
Teacher 匿名代码块
Teacher 构造器方法
分析:
但是值得讨论的是,他的总结有点乱,并且有问题,基于他的写法我重新总结了一遍
- 执行父类的静态代码块(如果是第一次调用方法),并初始化父类静态成员变量
- 执行子类的静态代码块(如果是第一次调用方法),并初始化子类静态成员变量
- 执行父类匿名代码块 + 父类的构造代码块,始化父类普通成员变量,执行父类的构造函数
- 执行子类匿名代码块 + 子类的构造代码块,初始化子类普通成员变量,执行子类的构造函数
因而不看代码,推理如下:
-
new Teacher(), 由于 Teacher继承 Person,因而按分析得
- (第一次调用Person)Person静态代码块 - "Person\t静态代码块"
- (第一次调用Teacher) Teacher静态代码块 - "Teacher\t静态代码块"
- Person 匿名代码块 - "Person\t匿名代码块"
- Person构造代码块 - "Person\t构造器方法"
- Teacher匿名代码块 - "Teacher\t匿名代码块"
- Teacher构造代码块 - "Teacher\t构造器方法"
-
上述的 3.4. / 5.6. 都可以认为是第一调用这个方法时,执行对象构造器之前要保证匿名代码块至少执行过一次
当我继续声明新的Teacher对象时,静态代码块就不会被执行了,只剩下匿名代码块和构造代码块
Application.java
package oop.app.mystatic;
public class Application {
public static void main(String[] args) {
Teacher teacher = new Teacher();
System.out.println("=============================");
Teacher teacher1 = new Teacher();
}
}
STDOUT
Person 静态代码块
Teacher 静态代码块
Person 匿名代码块
Person 构造器方法
Teacher 匿名代码块
Teacher 构造器方法
=============================
Person 匿名代码块
Person 构造器方法
Teacher 匿名代码块
Teacher 构造器方法
Process finished with exit code 0
可见分析结果和测试案例结论一致
静态导入包*
不建议使用
以 Math.random() 这个方法为例
package oop.app.mystatic;
import static java.lang.Math.random; // 静态导入包
public class Application {
public static void main(String[] args) {
System.out.println(random());
}
}
final 类
绝后的类,带有final关键字的类不允许被继承

浙公网安备 33010602011771号