关于Java继承,咱不得不说的4个要点

简介: 关于Java继承,咱不得不说的4个要点

目录


1.继承必须使用extends关键字


2.父类中非私有的属性和方法可以被子类继承


3.构造方法不能被继承,只能通过super关键字去调用


4.调用构造方法并不会创建对象,但是会初始化数据

创建对象的方式1.new关键字 + 构造方法

创建对象的方式2.classloader

创建对象的方式3.反射



微信截图_20230504231622.png


那么大家晚上好,我是今天晚上的主讲老师,我是兔哥。

Java的三大特性,继承、封装和多态。

今天,咱就来聊聊继承。虽然在Java内卷的今天,继承不一定会在面试中问到,但是,这个知识点是我们平时开发代码的重中之重。


因此,掌握Java继承非常有必要。


1.继承必须使用extends关键字


extends关键字代表我们可以继承一个父类,也叫超类。


比如,我有一个A类。


public class A {
    private String name = "A";
}


在新建一个B类,去继承A类


public class B extends A{
}


那么我们就说B类是A类的子类。Java不允许多继承,只允许单继承,但是可以多层继承。

什么是多层继承,就是我在新建一个C类,继承B类


public class C extends B{
}


2.父类中非私有的属性和方法可以被子类继承


我们一般会使用到的访问权限,就说public,protected和private三种。

A类有一个私有的name,子类无法访问,只能自己访问。


验证


1.png


2.png


如果我们换成public


public class A {
    public String name = "A";
}


3.png


都没有报错 , 验证成功!

不过,对于我们希望被子类继承的部分,可以用protected,意思是受保护的,允许传承给子类。

如果我们给name设置成protected,再看B和C类


4.png


一样不会报错。

但是,protected的属性,在其他包不能访问。(报错了)


5.png


Demo.java


public class Demo {
    public static void main(String[] args) {
        String name = new A().name;
        System.out.println(name);
    }
}


上面的代码是会报错的,同时,它也不能在A类的同一个包的子包中被访问到。


6.png


7.png

只能在同一个包中,或者自己的子类中被访问。

如果Demo也是A的子类


public class Demo extends A{
    public void show(){
        System.out.println(super.name);
    }
}


这是允许的,不会报错(哪怕不在一个包中),我们在B类和C类也能访问到name,但是需要用到super关键字。


让我们绕回来,总结下就是父类中非私有的属性和方法可以被子类继承!


如果不设置成public,会造成很多麻烦,其他包调用不到了!所以,父类一般就是给我们继承用的,而不是给你直接在其他地方调用的。


3.构造方法不能被继承,只能通过super关键字去调用


父类的构造方法是不能被继承的,但我们可以通过super关键字去调用。

当我们new一个B类对象,A类的构造器会优先调用。

当我们new一个C类对象,A类和B类的构造器会先后调用。

验证:


public class A {
    protected String name = "A";
    public A(){
        System.out.println("A");
    }
}


public class B extends A{
    public B(){
        System.out.println("B");
    }
}


public class C extends B{
    public C(){
        System.out.println("C");
    }
}


测试


public class Demo {
    public static void main(String[] args) {
       new C();
    }
}


结果


8.png


同样的,父类构造器必须是public或protected,如果用private,子类也无法使用


9.png


10.png


11.png


C类虽然编译不报错,但是运行一定报错。


12.png


父类构造器如果没有声明缺省的,却声明了有参构造器,则子类必须用super关键字调用父类的有参构造。


public class A {
    protected String name = "A";
    protected A(String name){
        System.out.println("A");
        this.name = name;
    }
}


B类报错


13.png


必须手动用super关键字调用一下父类的有参构造才行,哪怕你只是做做样子


public class B extends A{
    public B(){
        super(null);
        System.out.println("B");
    }
}


如果A类有多个构造器,但偏偏就是没有显式声明缺省构造


public class A {
    protected String name = "A";
    protected int price = 100;
    protected A(String name){
        System.out.println("A");
        this.name = name;
    }
    protected A(String name,int price){
        System.out.println("A");
        this.name = name;
        this.price = price;
    }
}


子类随便super一个父类的构造就行,但一定要有。


public class B extends A{
    public B(){
        super(null);
        System.out.println("B");
    }
}


这种也行


public class B extends A{
    public B(){
        super(null,1);
        System.out.println("B");
    }
}


看你具体的情况。


4.调用构造方法并不会创建对象,但是会初始化数据


我们举了这么多例子,不难发现,构造方法的作用只是初始化数据而已。


而我们创建对象是用new关键字配合构造方法的形式,所以我们可能会误认为调用构造方法就会创建对象了。


创建对象的方法,大体有三种:


创建对象的方式1.new关键字 + 构造方法


A a = new A("A",100);


创建对象的方式2.classloader


DiskClassLoader dcl = new DiskClassLoader("D:\\idea-workspace\\j2se\\out\\production\\j2se\\com\\javaxbfs\\bean");
/** 找到对应的class * */
Class<?> aClass = dcl.findClass("com.javaxbfs.bean.A");
/** 获取构造函数 * */
Constructor<?> constructor = aClass.getConstructor(String.class);
/** 用构造函数创建对象 * */
Object o = constructor.newInstance("A");
Method show = aClass.getMethod("show");
show.invoke(o);


DiskClassLoader是我们的自定义类加载器,用来加载磁盘上另外的class。DiskClassLoader的代码附在最后。


创建对象的方式3.反射


其实上面的例子已经用到了反射。


可见,构造方法只是用来初始化数据的,并不会新建一个对象。


而且,构造方法在当前类中,可以在其他构造方法中通过this调用,在子类构造方法中,可以通过super关键字调用(也只能出现在子类的构造方法中)。并且,必须是在方法的第一行。


最后,说说继承的好处,最大的好处,自然是代码的复用,缺点则是增加了耦合。


附上DiskClassLoader的代码:


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class DiskClassLoader extends ClassLoader {
    private String mLibPath;
    public DiskClassLoader(String path) {
        // TODO Auto-generated constructor stub
        mLibPath = path;
    }
    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        // TODO Auto-generated method stub
        String fileName = getFileName(name);
        File file = new File(mLibPath,fileName);
        try {
            FileInputStream is = new FileInputStream(file);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            int len = 0;
            try {
                while ((len = is.read()) != -1) {
                    bos.write(len);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            byte[] data = bos.toByteArray();
            is.close();
            bos.close();
            return defineClass(name,data,0,data.length);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return super.findClass(name);
    }
    //获取要加载 的class文件名
    private String getFileName(String name) {
        // TODO Auto-generated method stub
        int index = name.lastIndexOf('.');
        if(index == -1){
            return name+".class";
        }else{
            return name.substring(index+1)+".class";
        }
    }
}


相关文章
|
4天前
|
Java
Java中的继承和多态是什么?请举例说明。
Java中,继承让子类继承父类属性和方法,如`class Child extends Parent`,子类可重写父类方法。多态允许父类引用指向子类对象,如`Animal a = new Dog()`,调用`a.makeSound()`会根据实际对象类型动态绑定相应实现,增强了代码灵活性和可扩展性。
14 0
|
4天前
|
Java
Java基础—笔记—继承篇
该内容介绍了Java中的继承概念。继承允许子类从父类继承属性和方法,简化代码并提高复用性。格式是`public class 子类 extends 父类`。特点包括子类能访问非私有数据,方法可以被重写(@Override标记),但私有和静态方法不能重写。权限修饰符有private、缺省、protected和public。Java支持单继承和多层继承,所有类间接继承自Object类。继承后,成员访问遵循就近原则,this指代本类,super指代父类。子类构造器默认调用父类无参构造器,也可通过super调用有参构造器。
18 0
|
4天前
|
Java
在Java中,多态性是通过继承和接口实现的
【4月更文挑战第7天】在Java中,多态性是通过继承和接口实现的
22 1
|
4天前
|
搜索推荐 Java
Java的面向对象特性主要包括封装、继承和多态
【4月更文挑战第5天】Java的面向对象特性主要包括封装、继承和多态
21 3
|
4天前
|
Java
【Java开发指南 | 第二十四篇】Java继承
【Java开发指南 | 第二十四篇】Java继承
9 0
|
4天前
|
Java
【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
【Java开发指南 | 第九篇】访问实例变量和方法、继承、接口
14 4
|
4天前
|
Java
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
【JAVA基础篇教学】第五篇:Java面向对象编程:类、对象、继承、多态
|
4天前
|
Java 编译器 开发者
Java一分钟之-继承:复用与扩展类的特性
【5月更文挑战第9天】本文探讨了Java中的继承机制,通过实例展示了如何使用`extends`创建子类继承父类的属性和方法。文章列举了常见问题和易错点,如构造器调用、方法覆盖、访问权限和类型转换,并提供了解决方案。建议深入理解继承原理,谨慎设计类结构,利用抽象类和接口以提高代码复用和扩展性。正确应用继承能构建更清晰、灵活的代码结构,提升面向对象设计能力。
17 0
|
4天前
|
Java
java面向对象——包+继承+多态(一)-2
java面向对象——包+继承+多态(一)
18 3
|
4天前
|
SQL Java 编译器
java面向对象——包+继承+多态(一)-1
java面向对象——包+继承+多态(一)
17 2