Java – 面向对象(上)
简介
static
static 表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。
静态变量
1.被static修饰的成员变量,叫做静态变量。
特点:
1.被该类所有对象共享
2.不属于对象,属于类
3.随着类的加载而加载,优先于对象存在。
调用方式:类名调用(推荐)
对象实例名调用
静态变量最主要的目的是为了共享数据,如果有某个变量数据需要让所有实例所共享使用,可以把它设置成静态变量。
2.被static修饰的成员方法,叫做静态方法。
特点:
1.多用在测试类和工具类中
工具类一般是指一类不能也不需要描述事物的类,比如Person类是描述一个人类,而有一些事情是不需要描述的,比如 数组处理工具类。
2.javabean类中很少会使用
调用方式:
本类调用:直接调用
其它类调用:
1.类名调用(推荐)
2.对象名调用
注意:工具类需要阻止生成实例,所以需要定义私有的构造函数。
public class Util {
private Util() {
// 定义私有构造函数,防止实例化
}
}
static 注意事项:
1.静态方法只能访问静态变量和静态方法
2.非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法。
3.静态方法中是没有 this 关键字的
静态方法中,只能访问静态,非静态方法可以访问所有。静态方法中没有 this 关键字。
继承
Java中提供一个关键字 extends, 用这个关键字,我们可以让一个类和另一个类建立起继承关系。
Java只支持单继承,不支持多继承,但是支持多层继承。
多层继承指的是,子类 extends 父类 extends 爷类
Java中所有的类都直接或间接继承于Object 类
public class Student extends Person {}
Student 称为子类(派生类),Person 称为父类(基类、超类)
继承的好处
1.可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性
2.子类可以在父类的基础上,增加其他的功能,使子类更强大。
当类与类之间存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。
那些东西能被继承
Java中,构造方法是不能被继承的,不论是非私有的还是私有的都不能。
但是成员变量不管是私有的还是非私有的,子类都能被继承下来,但是子类不能被调用所以报错(不能调用不代表没有继承)。
而成员方法中,父类的私有方法子类不能被继承。
子类中所有构造方法默认先访问父类中的无参构造,再执行自己的构造。
因为子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使用父类数据。
子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化
子类构造方法中使用 super()
方法调用父类构造函数,如果不写,JVM会在编译时自动帮你加进去。
如果想调用父类有参构造方法,需要手动写 super(prop)
进行调用
public Zi() {
super(name);
}
继承调用中的顺序
Java 在调用变量和方法中,使用就近原则,谁离我近,我就调用谁
//父类
public class Fu {
String name = "Fu";
}
//子类
class Zi extends Fu{
String name = "Zi";
public void method(){
String name = "method";
System.out.println(name); // => "method"
}
}
就近原则,如果方法体内没有 name,才会输出子类的 name
//父类
public class Fu {
String name = "Fu";
}
//子类
class Zi extends Fu{
String name = "Zi";
public void method(){
System.out.println(name); // => "Zi"
}
}
那如果连子类都没有 name ,才会调用父类的 name
//父类
public class Fu {
String name = "Fu";
}
//子类
class Zi extends Fu{
public void method(){
System.out.println(name); // => "Fu"
}
}
那如何同时读取这三个变量?
使用 this 和 super
//父类
public class Fu {
String name = "Fu";
}
//子类
class Zi extends Fu{
String name = "Zi";
public void method(){
String name = "method";
System.out.println(name); // => "method"
System.out.println(this.name); // => "Zi"
System.out.println(super.name); // => "Fu"
}
}
this
this 理解为一个变量,表示当前方法调用者的地址值
super
super 代表父类存储空间
Java 中如果出现相同变量,只能调用到父类的,不能调用到爷类。
class Ye {
String Ye = "Ye";
}
//父类
public class Fu extends Ye{
String name = "Fu";
}
//子类
class Zi extends Fu{
String name = "Zi";
public void method(){
String name = "method";
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
System.out.println(super.super.name); // 会报错,不允许双层super
}
}
方法重写
重写:当父类的方法不能满足子类现在的需求时,需要进行方法重写
书写格式:在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。
@Override 重写注解
1.@Override 是放在重写后的方法上,校验子类重写时语法是否正确
2.加上注解后如果有红色波浪线,表示语法错误。
3.建议重写方法都加 @Override 注解,代码安全,优雅。
方法重写注意事项
1.重写方法的名称、形参列表必须与父类中的一致
2.子类重写父类方法时,访问权限子类必须大于等于父类(空着不写 < protected < public)
3.类重写父类方法时,返回值类型子类必须小于等于父类
4.建议重写的方法尽量和父类保持一致
5.只有被添加到虑方法表中的方法才能被重写。
多态
同类型的对象,表现出的不同形态。
多态表现形式
父类类型 对象名称 = new 子类对象
前提:
父类和子类需要有继承关系
父类引用指向子类对象
Fu f = new Zi()
有方法重写
多态调用成员特点
变量调用:编译看左边,运行也看左边
方法调用:编译看左边,运行看右边
变量调用
编译看左边:javac 编译代码的时候,会看到左边的父类中有没有这个变量,如果有,编译成功,如果没有,编译失败。
运行也看左边:java 运行代码的时候,实际获取的高是左边父类中的成员变量的值。
// 定义一个 父类 Animal
public class Animal {
String name = "动物"; // 如果父类不声明 name ,则下面实例化的 a.name 会报错不存在
public void show(){
System.out.println("动物------显示");
}
}
// 定义一个 子类Dog 继承父类 Animal
class Dog extends Animal{
String name = "狗子";
@Override
public void show() {
System.out.println("狗子------显示");
}
}
// 通过实例化
Animal a = new Dog();
// java 运行代码的时候,实际获取的高是左边父类中的成员变量的值。
System.out.println( a.name ); // => "动物"
方法调用
编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有,编译失败。
运行看右边:java运行代码的时候,实际上运行的是子类中的方法。
// 定义一个 父类 Animal
public class Animal {
String name = "动物";
public void show(){
System.out.println("动物------显示");
}
}
// 定义一个 子类Dog 继承父类 Animal
class Dog extends Animal{
String name = "狗子";
@Override
public void show() {
System.out.println("狗子------显示");
}
}
// 通过实例化
Animal a = new Dog();
// 调用 父类实例 a 时,编译期间会检查 Animal 中是否有 show() 方法,没有会报错
// 而在调用 a.show() 时,运行的却是 其子类 Dog 中的 show() 方法
a.show(); // => "狗子------显示"
多态的一些问题
1.不能使用特有的子类功能
从上面的方法调用我们可以知道,如果调用父类成员,执行子类方法的前提是,父类必须有相关方法,子类进行重写,但是如果子类独有的方法而父类没有,那么多态方法不能调父执行子。
public class Animal {
String name = "动物";
public void show(){
System.out.println("动物------显示");
}
}
class Dog extends Animal{
String name = "狗子";
@Override
public void show() {
System.out.println("狗子------显示");
}
public void eat(){
System.out.println("狗子在吃饭");
}
}
Animal a = new Dog();
a.show(); // => 可以执行,因为父类也有 show 方法
a.eat(); // => 报错且不能执行,因为父类没有 eat 方法
要解决这个问题,我们需要在执舻子类方法前,把类型转回子类,使用强转类型转换实现
Animal a = new Dog();
Dog d = (Dog) a
d.show(); // => "狗子------显示"
d.eat(); // => "狗子在吃饭"
类型判断
上面我们知道可以通过类型强转的方式转回子类并执行子类方法是可行的,但是如果我瞎转会如何:
Animal a = new Dog();
Cat c = (Cat) a
c.show();
c.eat();
Cat 也是 Animal 的子类,Dog 实例在执行时,强转为 Cat 类,编译不会报错,但是运行时会报错。
所以我们需要进行类型判断,使用 instanceof 关键字来判断是否为对应的子类类型,再进行方法调用。
Animal a = new Dog();
if(a instanceof Dog){
Dog d = (Dog) a
d.show();
d.eat();
}
在 JDK 14 中提供了新特性,可以在 instanceof 中加入变量省略转换表达式
Animal a = new Dog();
if(a instanceof Dog d){
d.show();
d.eat();
}
共有 0 条评论