Java基础学习 五 复用类(组合、继承、代理、重写、重载、protected关键字、向上/下转型、final关键字、初始化以及类的加载)

图片来自

 

组合语法   (一个类里面使用其他的对象或其他数据类型)

public class Person {
    // 使用其他对象或包装类数据类型作为成员变量称为组合语法 
    private String name,gender = "男";//声明时初始化
    private int age;
    private float height;
    Clothes myClothes = new Clothes();

    public Person(){
        System.out.println("Person()");
        System.out.println("gender"+gender);
        //构造器初始化
        age = 18;
    }
    {
        //实例初始化
        height = 185.4f;
    }
    @Override
    public String toString(){
        //延迟初始化又叫惰性初始化
        if (name == null){
            name = "张三";
        }
        return "name:"+name
                +" gender:"+gender
                +" age:"+age
                +" height:"+height
                +" myClothes"+myClothes;
    }
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person);
    }
}

class Clothes{
    private String s;
    Clothes(){
        System.out.println("Clothes()");
        s = "dress";
    }

    @Override
    public String toString(){
        return s;
    }
}

  继承语法 (利用现有类的类型创建新类  任何一个类都默认继承了object)

class Dog extends Animal {
    public Dog() {
        System.out.println(" Dog()");
    }

    @Override
    public void run() {
        this.append(" Dog run()");
        super.run();
    }
    public void eat(){ this.append(" Dog eat()");}

    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.run();
        dog.eat();
        System.out.println(dog);
        System.out.println("---------");
        Animal.main(args);
    }
}

public class Animal {
    private String s = "Animal";

    public Animal() {
        System.out.println(" Animal()");
    }

    public void append(String a){ this.s += a;}
    public void run(){ append(" Animal run()");}

    @Override
    public String toString() {
        return "Animal{" +
                "s='" + s + '\'' +
                '}';
    }

    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.run();
        System.out.println(animal);
    }
}

继承使用 extends 关键字 只能继承一个函数 属于单继承 

创建子类对象时 在调用子类构造器时会先调用父类的无参构造器  如果父类没有无参构造器 则子类的构造器应传入对应类型的值

代理(组合+继承)

public class SpaceShipControls {
    public void up(int velocity){
        System.out.println("SpaceShipControls up"+velocity);
    }
}
public class SpaceShip{
    private String name;
    private SpaceShipControls s = new SpaceShipControls();

    public SpaceShip(String name) {
        this.name = name;
    }
    // 代理 既有继承又有组合
    public void up(int velocity){
        s.up(velocity);
    }
    @Override
    public String toString() {
        return "SpaceShip{" +
                "name='" + name +
                '}';
    }

    public static void main(String[] args) {
        SpaceShip spaceShip = new SpaceShip("NASA");
        spaceShip.up(100);
        System.out.println(spaceShip);
    }
}

组合和继承一起使用  根据需要可以一起使用
 

重写(Override)

方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型

子类中不能重写父类中的final方法 
子类中必须重写父类中的abstract方法
 

public class Animal {
    public void run(){
        System.out.println(" Animal run() ");
    }
}
public class Dog extends Animal {
    @Override
    public void run() { //重写
        System.out.println(" Dog run()");
    }
}

 

重载(Overload)

方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同

不能根据返回类型区分

public class Dog{
    
    public void run() {
        System.out.println(" Dog run()");
    }
    public void run(int i){
        System.out.println(" Dog run() i:"+i);
    }
    public void run(char c){
        System.out.println(" Dog run() c:"+c);
    }
    public void run(int i,char c){
        System.out.println(" Dog run() i:"+i+" c:"+c);
    }
    public void run(char c,int i){
        System.out.println(" Dog run() c:"+c+" i:"+i);
    }
}

详细解释

protected关键字

public class Dog extends Animal{

    public Dog(String name) {
        super(name);
    }

    public void change(String name){
        changeName(name);
    }

    @Override
    public String toString() {
        return super.toString();
    }

    public static void main(String[] args) {
        Dog dog = new Dog("小黄");
        System.out.println(dog);
        dog.change("旺财");
        System.out.println(dog);
    }
}

class Animal {
    private String name;

    public Animal(String name){
        this.name = name;
    }

    protected void changeName(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return name + "run";
    }
}

向上/下转型

public class Dog extends Animal {
    @Override
    public void eat(){
        System.out.println("Dog eat");
    }
    public void run(){
        System.out.println("dog run");
    }
    public static void main(String[] args) {
        //向上转型
        Animal a = new Dog();
        a.eat();
        //a.run();//出错

        //向下转型
        Dog d = (Dog)a;
        d.eat();
        d.run();
    }
}
class Animal {
    public void eat() {
        System.out.println("Animal eat");
    }
}

总结:1. 父类引用可以只想子类对象 而子类引用不能指向父类对象

           2. 子类对象赋给父类引用 为向上转型 不用强制转换

           3. 把指向子类对象的父类引用赋给 子类引用叫向下转型 要强制转换

           4. 如果把父类作为参数 调用时传入子类对象 利用向上转型 使代码变得简介 一个方法能接收所有子类对象 体现了java的抽象编程思想

           5. 如果父类的引用指向的是父类的对象 此时向下转型就会抛出异常

public class Dog extends Animal {
    @Override
    public void eat(){
        System.out.println("Dog eat");
    }
    public void run(){
        System.out.println("dog run");
    }
    public static void main(String[] args) {
        Animal animal = new Animal();

        //编译期不会检测到 如果运行就会出错
        Dog dog = (Dog) animal;
        dog.eat();
    }
}
class Animal {
    public void eat() {
        System.out.println("Animal eat");
    }
}

 Exception in thread "main" java.lang.ClassCastException: mypackage.Animal cannot be cast to mypackage.Dog
    at mypackage.Dog.main(Dog.java:20)

           6.  通过instanceof关键字能判断这个对象是否是这个特定类或者是它的子类的一个实例

public static void main(String[] args) {
        Animal animal = new Animal();

        // 判断这个对象是否是这个特定类或者是它的子类的一个实例
        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.eat();
        }else {
            animal.eat();
        }

    }

final关键字

  可作用于变量: 

public class FinalData {
    private static Random random = new Random(47);
    private String id;
    public FinalData(String id){
        this.id = id;
    }
    private final int valueOne = 9;  //不可改变
    private static final int VALUE_TWO = 99;  //不可改变
    public static final int VALLUE_THREE = 39; //不可改变
    //实例成员 在同一个对象中不可改变 不同对象的同一个变量不一定一样
    private final int i4 = random.nextInt(20);
    // 静态成员只实例化一次 在不同对象中同一个变量值一样
    private static final int INT_5 = random.nextInt(20);

    private Value v1 = new Value(11);  // v1的引用的对象可以改变
    private final Value v2 = new Value(22); //v2 引用的对象不能改变 但对象中的属性值能改变

    //引用的对象不能改变 但对象中的属性值能改变
    private static final Value VAL_3 = new Value(33);
    private final int[] a = {1,2,3,4,5,6}; // a数组引用不能改变 但数组中的值能改变
    private static final int[] B = {1,2,3,4,5,6}; // B数组引用不能改变 但数组中的值能改变
    @Override
    public String toString(){
        return id+": i4 = " +i4+",INT_5 = "+INT_5;
    }

    public static void main(String[] args) {
        FinalData fd1 = new FinalData("fd1");
//        fd1.valueOne = 3;  final修饰的变量 不能被赋值
        fd1.v2.i = 7;
        fd1.v1 = new Value(9);
        for (int i = 0;i<fd1.a.length;i++){
            fd1.a[i]++;
        }
        System.out.println(fd1.v1.toString());
        System.out.println(Arrays.toString(fd1.a));
        System.out.println(fd1);
        System.out.println("新的数据");
        FinalData fd2 = new FinalData("fd2");
        System.out.println(fd2);
    }

}

class Value{
    int i;
    public Value(int i){
        this.i = i;
    }

    @Override
    public String toString() {
        return "Value{" +
                "i=" + i +
                '}';
    }
}

  空白final:定义成final但是没有初始化复制,可以延申都使用的时候 ,但必须在使用之前对其初始化复制

public class FinalData {
    private final int i = 0;
    private final int j;  //声明空的final时 必须使用构造函数初始化
    private final Value v;//声明空的final时 必须使用构造函数初始化
    public FinalData(int j, Value v) {
        this.j = j;
        this.v = v;
    }
    public FinalData(final int x){  //可以使用final变量修饰参数 修饰的参数不能改变
        this.j = x;
        this.v = new Value(x);
    }
}
class Value{
    int i;
    public Value(int i){
        this.i = i;
    }
}

  可作用于方法:防止所有子类修改 子类不能覆盖    私有的方法 不能被子类覆盖 所以private 和final 共同修饰方法没有意义

public class Main{
    public static void main(String[] args) {
        Value value = new Value();
        value.f();
        value.g();
        FinalData finalData = value;
        //进行强制转换能输出子类的方法 如果不强制转化会报错 因为父类的方法不可见
        ((Value) finalData).f();  
        finalData.g();
    }
}
class FinalData {
    private void f(){ System.out.println("FinalDate f()"); }
    final void g(){ System.out.println("FinalDate g()"); }
}
class Value extends FinalData{
    //于finalData 中的f方法不是继承关系 因为是私有的不能覆盖
    public void f(){  System.out.println("Value f()"); }
    // final 修饰的方法不能被重写
    //public void g(){ System.out.println("Value g()"); }
}

 

          扩展:

             输出结果 :

            分析: private 修饰的方法属于静态绑定 在编译期 就跟类绑定在了一起 所以调用 的时候是调用的父类的f()方法

                虽然父类的引用 指向的是子类的对象但是父类的f() 方法对子类来说是不可见的 所以子类也不能覆盖 而p引用只能调用子类覆盖的方法 但是子类的f()方法没有覆盖父类的方法所以调用不到子类的f()方法这时候因为启动入口在PrivateOverride中 当程序启动时能直接调用父类的f()方法 如果启动入口不在父类的方法中则会报错

                加上强制转换则会强制转换为子类的对象并调用子类的方法            感觉自己写的好罗嗦啊。。。。

  可作用于   类: 被final修饰的类不能被继承  String类就是final修饰的不能继承

初始化以及类的加载 

public class Beetle extends Insect {
    private int k = printInit("Beetle.k initialized");
    public Beetle(){
        System.out.println("k = " + k);
        System.out.println("j = " + j);
    }
    private static int x2 = printInit("static Beetle.x2 initialized");

    public static void main(String[] args) {
        System.out.println("Beetle constructor");
        Beetle b = new Beetle();
    }
}
class Insect{
    private int i = 9;
    protected int j;
    Insect(){
        System.out.println("i = "+i+",j = "+j);
        j = 39;
    }
    private static int x1 = printInit("static Insect.x1 Initialized");
    static int printInit(String s){
        System.out.println(s);
        return 47;
    }
}

输出结果:

执行顺序: 运行程序 因为静态 main方法 在Beetle类 类加载器会加载Beetle的class文件 检测到Beetle有基类 则会加载基类的class文件 所以

     第一步加载 基类的静态成员变量 

     第二步 加载子类的静态成员变量 

     第三步 加载Beetle的main方法

     第四步 main方法中创建Beetle对象  加载Beetle的 父类 构造方法  

     第五步  加载Beetle 对实例成员初始化

     第六步  加载Beetle的构造方法

 

                  注意: static修饰的变量和方法只初始化一次 在第一次用到这个类的时候静态变量进行初始化  不一定是在new 这个对象的时候初始化。可能是 类.静态方法或成员 这时候也算是用到了这个类 则会把这个类的静态变量进行初始化;如果用到了这个类的静态方法则会初始化用到的静态方法,没有用到的则不会进行初始化。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小马也是行动派

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值