JAVA-面向对象进阶

static(静态)

  • 关于static关键字的使用,它可以用来修饰的成员变量和成员方法
  • 被static修饰的成员是属于类的是放在静态区中
  • 没有static修饰的成员变量和方法则是属于对象的。

静态变量及其访问

static修饰成员变量,说明这个成员变量是属于类的,这个成员变量称为类变量或者静态成员变量直接用类名访问即可,所有的对象都可以共享这个方法。
因为类只有一个,所以静态成员变量在内存区域中也只存在一份。所有的对象都可以共享这个变量。

实例变量及其访问

static修饰的成员变量属于每个对象的, 这个成员变量叫实例变量,之前我们写成员变量就是实例成员变量。

需要注意的是:实例成员变量属于每个对象,必须创建类的对象才可以访问。

区分:

类.类变量(类.静态成员变量) 对象.实例成员变量    

继承

  • 继承描述的是事物之间的所属关系

  • 父类更通用,子类更具体

  • 继承:就是子类继承父类的属性行为,使得子类对象可以直接具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。

父类中的私有成员变量,子类是不能直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,通过父类中提供公共的getXxx方法setXxx方法进行访问。

继承的好处

  • 提高代码的复用性(减少代码冗余,相同代码重复利用)。
  • 使类与类之间产生了关系。

定义格式 extends

class 父类 {
	...
}

class 子类 extends 父类 {
	...
}

注意:Java是单继承的,一个类只能继承一个直接父类

super访问父类成员变量

子父类中出现了同名的成员变量时,子类会优先访问自己对象中的成员变量。

  • 子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用super 关键字,修饰父类成员变量

注意:super代表的是父类对象的引用,this代表的是当前对象的引用。

class Fu {
    // Fu中的成员变量。
    int num = 5;
}
 
class Zi extends Fu {
    // Zi中的成员变量
    int num = 6;
   
    public void show() {
        int num = 1;
       
        // 访问方法中的num
        System.out.println("method num=" + num);
        // 访问子类中的num
        System.out.println("Zi num=" + this.num);
        // 访问父类中的num
        System.out.println("Fu num=" + super.num);
    }
}
 
class Demo {
    public static void main(String[] args) {
        // 创建子类对象
        Zi z1 = new Zi(); 
        // 调用子类中的show方法
        z1.show(); 
    }
}
 
演示结果:
method num=1
Zi num=6
Fu num=5
  • 方法重名
    如果子类父类中出现重名的成员方法,则创建子类对象调用该方法的时候,子类对象会优先调用自己的方法。

  • 方法重写
    子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现

  • 重写使用
    子类继承了父类的方法,但是子类觉得父类的这方法不足以满足自己的需求,子类重新写了一个与父类同名的方法,以便覆盖父类的该方法

@Override重写注解

  • @Override:注解,重写注解校验!

  • 这个注解标记的方法,就说明这个方法必须是重写父类的方法,否则编译阶段报错。

  • 建议重写都加上这个注解,一方面可以提高代码的可读性,一方面可以防止重写出错!

加上后的子类代码形式如下:

public class Cat extends Animal {
     // 声明不变,重新实现
    // 方法名称与父类全部一样,只是方法体中的功能重写写了!
    @Override
    public void cry(){
        System.out.println("我们一起学猫叫,喵喵喵!喵的非常好听!");
    }
}
  • 注意事项
  1. 方法重写是发生在子父类之间的关系。
  2. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
  3. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样
  4. 子类构造方法执行的时候,都会在第一行默认先调用父类无参数构造方法一次。
  5. 子类构造方法的第一行都隐含了一个super()去调用父类无参数构造方法,super()可以省略不写。

super和this的用法格式

访问成员:

this.成员变量       --    本类的
super.成员变量      --    父类的
 
this.成员方法名()    --    本类的    
super.成员方法名()   --    父类的

调用构造方法格式:

super(...) -- 调用父类的构造方法,根据参数匹配确认
this(...) -- 调用本类的其他构造方法,根据参数匹配确认

注意:

  • 子类的每个构造方法中均有默认的super(),调用父类的空参构造。手动调用父类构造会覆盖默认的super()。

  • super() 和 this() 都必须是在构造方法的第一行,所以不能同时出现。

  • super(..)和this(...)是根据参数去确定调用父类哪个构造方法的。

  • super(..)可以调用父类构造方法初始化继承自父类的成员变量的数据。

  • this(..)可以调用本类中的其他构造方法。

public class Animal {
    //姓名,年龄,颜色
    private String name;
    private int age;
    private String color;
 
 
    public Animal() {
    }
 
    public Animal(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    public String getColor() {
        return color;
    }
 
    public void setColor(String color) {
        this.color = color;
    }
}
 
 
public class Cat extends Animal{
    //因为猫类中没有独有的属性。
    //所以此时不需要写私有的成员变量
 
    //空参
    public Cat() {
    }
 
    //需要带子类和父类中所有的属性
    public Cat(String name, int age, String color) {
        super(name,age,color);
    }
}
 
 
public class Dog extends Animal{
    //Dog :吼叫
    private String wang;
 
    //构造
    public Dog() {
    }
 
    //带参构造:带子类加父类所有的属性
    public Dog(String name, int age, String color,String wang) {
        //共性的属性交给父类赋值
        super(name,age,color);
        //独有的属性自己赋值
        this.wang = wang;
    }
 
    public String getWang() {
        return wang;
    }
 
    public void setWang(String wang) {
        this.wang = wang;
    }
}
 
public class Demo {
    public static void main(String[] args) {
        //Animal : 姓名,年龄,颜色
        //Cat :
        //Dog :吼叫
 
        //创建狗的对象
        Dog d = new Dog("旺财",2,"黑色","嗷呜~~");
        System.out.println(d.getName()+", " + d.getAge() + ", " + d.getColor() + ", " + d.getWang());
 
        //创建猫的对象
        Cat c = new Cat("中华田园猫",3,"黄色");
        System.out.println(c.getName() + ", " + c.getAge() + ", " + c.getColor());
    }
}

继承的特点

  1. Java只支持单继承,不支持多继承。

一个类只能有一个父类,不可以有多个父类。

  1. 一个类可以有多个子类。

  2. 可以多层继承。

多态

多态: 是指同一行为,具有多个不同表现形式。

多态体现的格式

父类类型 变量名 = new 子类/实现类构造器;
变量名.方法名();

多态的前提:有继承关系,子类对象是可以赋值给父类类型的变量。例如Animal是一个动物类型,而Cat是一个猫类型。Cat继承了Animal,Cat对象也是Animal类型,自然可以赋值给父类类型的变量。

多态的应用示例:

父类:
public class Person {
    private String name;
    private int age;
 
    空参构造
    带全部参数的构造
    get和set方法
 
    public void show(){
        System.out.println(name + ", " + age);
    }
}
 
子类1public class Administrator extends Person {
    @Override
    public void show() {
        System.out.println("管理员的信息为:" + getName() + ", " + getAge());
    }
}
 
子类2public class Student extends Person{
 
    @Override
    public void show() {
        System.out.println("学生的信息为:" + getName() + ", " + getAge());
    }
}
 
子类3public class Teacher extends Person{
 
    @Override
    public void show() {
        System.out.println("老师的信息为:" + getName() + ", " + getAge());
    }
}
 
测试类:
public class Test {
    public static void main(String[] args) {
        //创建三个对象,并调用register方法
 
        Student s = new Student();
        s.setName("张三");
        s.setAge(18);
 
        Teacher t = new Teacher();
        t.setName("王建国");
        t.setAge(30);
 
        Administrator admin = new Administrator();
        admin.setName("管理员");
        admin.setAge(35);

        register(s);
        register(t);
        register(admin);
  }
    //这个方法既能接收老师,又能接收学生,还能接收管理员
    //只能把参数写成这三个类型的父类
    public static void register(Person p){
        p.show();
    }
}

多态的运行特点

调用成员变量时:编译看左边,运行看左边

调用成员方法时:编译看左边,运行看右边

代码示例:

Fu f = new Zi();
//编译看左边的父类中有没有name这个属性,没有就报错
//在实际运行的时候,把父类name属性的值打印出来
System.out.println(f.name);
//编译看左边的父类中有没有show这个方法,没有就报错
//在实际运行的时候,运行的是子类中的show方法
f.show();

多态编译阶段是看左边父类类型的,如果子类有独有的功能,此时多态的写法就无法访问子类独有功能,所以多态的弊端是:

  • 多态无法访问子类独有功能

多态的前提

  • 有继承或者实现关系

  • 方法的重写【意义体现:不重写,无意义】@Override

  • 父类引用指向子类对象【格式体现】

父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

引用类型转换(转型)

多态无法访问子类独有功能

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

回顾基本数据类型转换

  • 自动转换: 范围小的赋值给范围大的.自动完成:double d = 5;
  • 强制转换: 范围大的赋值给范围小的,强制转换:int i = (int)3.14

多态的转型分为向上转型(自动转换)与向下转型(强制转换)两种。

向上转型(自动转换)

  • 向上转型:多态本身是子类类型向父类类型向上转换(自动转换)的过程,这个过程是默认的。
    当父类引用指向一个子类对象时,便是向上转型。

使用格式:

父类类型  变量名 = new 子类类型();
如:Animal a = new Cat();

原因是:父类类型相对与子类来说是大范围的类型,Animal是动物类,是父类类型。Cat是猫类,是子类类型。Animal类型的范围当然很大,包含一切动物。所以子类范围小可以直接自动转型给父类类型的变量。

向下转型(强制转换)

  • 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。
    一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

使用格式:

子类类型 变量名 = (子类类型) 父类变量名;
如:Aniaml a = new Cat();
   Cat c =(Cat) a;  

案例演示

定义类:

abstract class Animal {  
    abstract void eat();  
}  
 
class Cat extends Animal {  
    public void eat() {  
        System.out.println("吃鱼");  
    }  
    public void catchMouse() {  
        System.out.println("抓老鼠");  
    }  
}  
 
class Dog extends Animal {  
    public void eat() {  
        System.out.println("吃骨头");  
    }  
    public void watchHouse() {  
        System.out.println("看家");  
    }  
}

定义测试类:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();                // 调用的是 Cat 的 eat
 
        // 向下转型  
        Cat c = (Cat)a;       
        c.catchMouse();         // 调用的是 Cat 的 catchMouse
    }  
}

转型的异常

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat
 
        // 向下转型  
        Dog d = (Dog)a;       
        d.watchHouse();        // 调用的是 Dog 的 watchHouse 【运行报错】
    }  
}

这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。

instanceof关键字

为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

变量名 instanceof 数据类型 
如果变量属于该数据类型或者其子类类型,返回true。
如果变量不属于该数据类型或者其子类类型,返回false

所以,转换前,我们最好先做一个判断,代码如下:

public class Test {
    public static void main(String[] args) {
        // 向上转型  
        Animal a = new Cat();  
        a.eat();               // 调用的是 Cat 的 eat
 
        // 向下转型  
        if (a instanceof Cat){
            Cat c = (Cat)a;       
            c.catchMouse();        // 调用的是 Cat 的 catchMouse
        } else if (a instanceof Dog){
            Dog d = (Dog)a;       
            d.watchHouse();       // 调用的是 Dog 的 watchHouse
        }
    }  
}

instanceof新特性

JDK14的时候提出了新特性,把判断和强转合并成了一行

//新特性
//先判断a是否为Dog类型,如果是,则强转成Dog类型,转换之后变量名为d
//如果不是,则不强转,结果直接是false
if(a instanceof Dog d){
    d.lookHome();
}else if(a instanceof Cat c){
    c.catchMouse();
}else{
    System.out.println("没有这个类型,无法转换");
}
posted @   lanercifang  阅读(22)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示