我的编程经历(26)----------面向对象编程

本片总重点总结Java部分语法知识。

1.包和类

在IDEA上写代码的时候,执行 部分命令时会需要一些IDEA本身自带的关键字。而为了能使这些关键字生效,就需要进行引用,而引用置于顶部,用import进行表示。如:

import java.util.Arrays 

这代码的意思是引用java文件中util包中的Arrays这个类。而所谓的包就是对一个类的总体的囊括。在平常写代码的时候一般都是建立一个包,在包中进行代码的书写。当然,在一个类中写代码时所要应用的本身就已经封装好的关键字肯定不止一个,这个时候可以一一将其在顶部进行列举,也可以选择使用通配符:

import java.util.*;

其意义是导入这个包下的所有类,但并非如C语言中的直接全部导入,而是当要使用哪个时,再导用哪个。

2.继承

在此之前先定义两个类,以鸟和狗这两个动物为例:

class Dog {
    public String name;
    public int age;
    public void eat (){
        System.out.println("eat");
    }
}

class Bird{
    public String name;
    public int age;
    public void eat (){
        System.out.println("eat");
    }
    public void fly (){
        System.out.println("flu");
    }
}

可以看到鸟与狗这两个类存在一些相同的对象和属性。可以将这些相同的属性抽取出来,再引用到这两个类中,就作为继承,其关键字是extends:

class Animal{
    public String name;
    public int age;
    public void eat (){
        System.out.println("eat");
    }
}

class Dog extends Animal{

}

class Bird extends Animal{
    public String wing;
    public void fly (){
        System.out.println("flu");
    }
}
public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}

继承后就可以在main函数中new一个对象,对相应类中的对象进行访问。此时就可以使用构造方法新建一个对象,其中抽象出的共同点所组成的类被成为父类,而继承的类则为子类:

class Animal{
    public String name;
    public int age;
    public void eat (){
        System.out.println("eat");
    }
    public Animal(String name, int age){
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animal{
    public  Dog(String name, int age){
        super(name, age);
    }
}

class Bird extends Animal{
    public String wing;
    public void fly (){
        System.out.println(name + "flu" + age + wing);
    }
    public  Bird(String name, int age, String wing){
        super(name, age);
        this.wing = wing;
    }
}
public class Main {
    public static void main(String[] args) {
        Bird bird = new Bird("xixi", 10, "四处飞翔");
        bird.fly();
    }
}

在这段代码中要注意:在对狗和鸟使用构造函数进行初始化时,要优先对其继承的父类进行初始化,因此要使用super。其用法与this类似分为三种:

super()调用父类的构造方法,注意这个代码只能放在构造函数的第一行,也就是说其表示的是对父类对象的引用,因此不能在静态方法中使用。

super.func()调用父类的普通方法。

super.data调用父类的成员属性。

有些注意事项:若子类与父类有着同名的属性,会优先子类自身的字段而非父类字段。除非用super进行指定。

3.protected和final

protected与public相同都是用于修饰限定对象的。但是protected范围要更小一些。在对类成员变量进行修饰时使用public和private是两个极端,因此可以使用protected,只有在不同包中的非子类,才访问不到,其他均可访问。

final则是不可修改。一般来说继承关系不要大于三层,否者就过于累赘。当一个继承方法不再需要进行继承时就可以用final进行修饰,避免套娃似继承。

4.多态中的向上转型

向上转型就是指在父子类中,将子类的类型转换位父类的类型。大致有三种方式:直接赋值,方法传参,方法返回:

public class Main {
    //方法传参
    public static void func(Animal animal){
        animal.name = "hhhhha";
    }
    //作为函数的返回值
    public static Animal func2(Bird bird){
        bird.name = "hhhhhc";
        return  bird;
    }
    public static void main(String[] args) {
        //直接赋值
        Animal animal = new Bird("haha", 18, "自由飞翔");
        Bird bird = new Bird("haha", 18, "自由飞翔");
    }

在进行向上转型后,访问的对象和属性是以父类我主的,也就是说只能访问父类存在的方法和属性:

class Animal{
    public String name;
    public int age;
    public void eat (){
        System.out.println("eat");
    }
    public Animal(String name, int age){
        this.name = name;
        this.age = age;
    }
}

class Dog extends Animal{
    public  Dog(String name, int age){
        super(name, age);
    }
}

class Bird extends Animal{
    public String wing;
    public void fly (){
        System.out.println(name + "flu" + age + wing);
    }
    public  Bird(String name, int age, String wing){
        super(name, age);
        this.wing = wing;
    }
    public static void func(Animal name){
        System.out.println(name);
    }
}
public class Main {
    public static void main(String[] args) {
        //直接赋值
        Animal animal = new Bird("haha", 18, "自由飞翔");
        animal.eat();
    }
}

如这个代码,animal.fly()就会报错。那如果父类与子类同时存在某种属性或方法呢?在Bird中再添加一个方法并在main中进行访问

class Bird extends Animal{
    public String wing;
    public void fly (){
        System.out.println(name + "flu" + age + wing);
    }
    public void eat(){
        System.out.println("细嚼慢咽");
    }
    public  Bird(String name, int age, String wing){
        super(name, age);
        this.wing = wing;
    }
    public static void func(Animal name){
        System.out.println(name);
    }
}

这个时候若使用animal.eat进行访问,得到的就不再是父类中的“eat”, 而是子类中自己的“细嚼慢咽”,这其中发生了动态绑定。至于如何发生,可以通过字节码文件,反编译看到其过程,字节码文件都在out文件夹中的production中:

                                                                              

 在这里可以看到在编译的时候实际上都还是调用的父类的方法,但在执行之后,由于子类中有相同的方法,其调用方法发生了改变,绑定为子类的方法。称为动态绑定。而要发生动态绑定,其条件为

1.父类引用。引用的是子类对象

2.通过这个父类引用调用父类和子类同名的覆盖方法,即重写。

重写的条件为:

1.方法名相同

2.参数列表完全相同

3.返回值相同

4.在父子类情况下才能发生重写

也就是说,由于在这个代码中在子类中重写了父类中的方法,因此而发生动态绑定,调用了子类的方法而非调用父类的方法

但是重写也有着注意事项:

1.静态方法不能重写

2.子类访问修饰符访问要大于或等于父类

3.private方法和被final修饰的方法不能重写。

还有一个非常偏的类型,协变类型:构成重写但返回值类型不一样。

既然存在动态绑定,那肯定也有静态绑定,即根据所给的参数推导出调用哪个函数。重载就是典型的静态绑定。

5.多态中的向下转型

向下转型不太建议使用,要先进行强转,可能会造成代码bug问题。

-------------------------------------最后编辑于2023.4.11下午四点左右

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值