equals方法与==、组合、多态、转型、简单工厂模式、final及abstract关键字

1. 继承中的父子类同名情况

1.1 父子类方法同名情况

如果父子类方法同名,那么子类便重写的其父类的同名方法,后期子类对象调用该方法执行的是子类重写的方法,子类可通过super关键字访问父类同名方法。


/**
 * 功能:父子类方法同名情况
 */

//父类
class Father{
    //默认无参构造器
    public Father(){
        super();//默认隐式调用其父类(Object类)构造器
    }
    //父类方法
    public void test(){
        System.out.println("执行了父类方法");
    }
}

//子类
class Child extends Father{
    //默认无参构造器
    public Child(){
        super();//默认隐式调用父类(Father类)构造器
    }
    //子类同名方法
    public void test(){
        super.test();//调用父类的test方法
        System.out.println("执行了子类同名方法, 重写了父类test方法");
    }
}

public class Test {
    public static void main(String[] args) {
        Child c=new Child();//创建子类对象
        c.test();//调用的是子类重写的test方法

        Father f1=new Father();//创建父类对象
        f1.test();//调用的是父类test方法

        Father f2=new Child();//创建子类对象将其赋值给父类的引用变量
        f2.test();//调用的是子类重写的test方法,实现了多态
    }
}

1.2 父子类变量同名情况

父子类同名变量会开辟各自的存储空间,互不干扰,子类可用过super关键字访问父类同名变量。

/**
 * 功能:父子类变量同名情况
 */

//父类
class Father{

    String test="父类的test变量";

    //默认无参构造器
    public Father(){
        super();//默认隐式调用其父类(Object类)构造器
    }
}

//子类
class Child extends Father{

    String test="子类的同名test变量";
    {
        test=super.test;//子类访问父类的同名变量
    }

    //默认无参构造器
    public Child(){
        super();//默认隐式调用父类(Father类)构造器
    }
}

public class Test {
    public static void main(String[] args) {
        Child c=new Child();//创建子类对象
        System.out.println(c.test);;//访问的是子类同名的test变量

        Father f1=new Father();//创建父类对象
        System.out.println(f1.test);;//调用的是父类test变量

        Father f2=new Child();//创建子类对象将其赋值给父类的引用变量
        System.out.println(f2.test);;//调用的是父类的test变量,变量不能实现多态
    }
}

2. 继承条件下构造方法的执行顺序

  1. 子类构造方法的第一条语句为默认的隐式super()语句,用来调用父类的无参构造方法
//父类
class Father{
    //默认的隐式无参构造方法
    public Father(){
        super();//默认的隐式super语句,作用时调用父类的默认隐式无参构造方法(Father的父类是顶级类Object类)
    }
}

//子类
class Child extends Father{
    //默认的隐式无参构造方法
    public Child(){
        super();//默认的隐式super语句,作用是调用父类的默认隐式无参构造方法
    }
}
  1. 可以改写为显式的super(arguments)语句来实现调用父类的有参构造方法
//父类
class Father{
    //默认的隐式无参构造方法
    public Father(){
        super();//默认的隐式super语句,作用时调用父类的默认隐式无参构造方法(Father的父类是顶级类Object类)
    }

    //提供显式有参构造方法
    public Father(String args){

    }
}

//子类
class Child extends Father{
    //默认的隐式无参构造方法
    public Child(){
        super("args");//显式的super语句,调用父类显式有参构造方法
    }
}
  1. 也可以改写为显式的this(arguments)语句来实现调用本类的有参构造方法
//父类
class Father{
    //默认的隐式无参构造方法
    public Father(){
        super();//默认的隐式super语句,作用时调用父类的默认隐式无参构造方法(Father的父类是顶级类Object类)
    }

    //提供显式有参构造方法
    public Father(String args){

    }
}

//子类
class Child extends Father{
    //默认的隐式无参构造方法
    public Child(){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args, String argss){
        this(args);//调用本类显式有参构造方法
    }
}
  1. 构造方法中不能同时出现this与super语句来调用构造方法,但可以同时出现this和super语句来调用属性或非构造方法,但调用构造方法的语句必须是第一条语句
//父类
class Father{
    //默认的隐式无参构造方法
    public Father(){
        super();//默认的隐式super语句,作用时调用父类的默认隐式无参构造方法(Father的父类是顶级类Object类)
    }

    //提供显式有参构造方法
    public Father(String args){

    }
}

//子类
class Child extends Father{
    //默认的隐式无参构造方法
    public Child(){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args, String argss){
        super();//报错
        this(args);//调用本类显式有参构造方法
    }
}
//父类
class Father{
    //父类成员变量
    String test;

    //默认的隐式无参构造方法
    public Father(){
        super();//默认的隐式super语句,作用时调用父类的默认隐式无参构造方法(Father的父类是顶级类Object类)
    }

    //提供显式有参构造方法
    public Father(String args){

    }
}

//子类
class Child extends Father{
    //子类成员变量
    String test;

    //默认的隐式无参构造方法
    public Child(){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args){
        super();//隐式的super语句,调用父类隐式无参构造方法
    }

    //显式有参构造方法
    public Child(String args, String argss){
        this(args);//调用本类显式有参构造方法
        String test=this.test;//通过this调用本类属性
        test=super.test;//通过super调用父类属性
    }
}
  1. 建议显式添加默认的隐式无参构造方法

3. ==与equals()

==与equals()都可以对两个变量进行内容判断,如果相同返回true,如果不同返回false

3.1 ==

因为==操作的是栈数据,所以如果变量是基本数据类型,那么比较的是该变量的数值,如果是引用数据类型,比较的则是两个变量的地址值

//测试类
class Test2{
    //成员变量
    int b;
    //默认的无参构造方法
    public Test2(){

    }
    //构造方法重载
    public Test2(int b){
        this.b=b;
    }
}

public class Test {
    public static void main(String[] args) {

        //基本数据类型
        int a1=10;
        int a2=20;
        int a3=10;
        System.out.println(a1==a2);//输出结果:false
        System.out.println(a1==a3);//输出结果:true
        System.out.println(a1);//输出结果:10
        System.out.println(a2);//输出结果:20
        System.out.println(a3);//输出结果:10

        //引用数据类型
        Test2 b1=new Test2(10);
        Test2 b2=new Test2(20);
        Test2 b3=new Test2(10);
        System.out.println(b1==b2);//输出结果:false
        System.out.println(b1==b3);//输出结果:false
        System.out.println(b1);//输出结果:cn.khue.csdn.Test2@3f3afe78
        System.out.println(b2);//输出结果:cn.khue.csdn.Test2@7f63425a
        System.out.println(b3);//输出结果:cn.khue.csdn.Test2@36d64342
    }
}

3.2 equals()

equals()操作的是堆数据,但是Object类的equals()方法比较的两个变量的地址值,所以在调用该方法时需要重写

//测试类
class Test2{
    //成员变量
    int b;
    //默认的无参构造方法
    public Test2(){

    }
    //构造方法重载
    public Test2(int b){
        this.b=b;
    }
}

public class Test {
    public static void main(String[] args) {

        //引用数据类型
        Test2 b1=new Test2(10);
        Test2 b2=new Test2(20);
        Test2 b3=new Test2(10);
        System.out.println(b1.equals(b2));//输出结果:false
        System.out.println(b1.equals(b3));//输出结果:false
    }
}

重写equals方法后:

//测试类
class Test2{
    //成员变量
    int b;
    //默认的无参构造方法
    public Test2(){

    }
    //构造方法重载
    public Test2(int b){
        this.b=b;
    }

    //equals方法重写
    @Override
    public boolean equals(Object obj) {
        Test2 t2=(Test2)obj;//因为传进的对象为Object类型,而我们要比较的时Test2类,所以需要向下转型

        //判断传入的对象是否为空,如果为空,直接返回false
        if(t2==null){
            return false;
        }

        //判断传入的对象是否是同一个对象,如果是,直接返回true
        if(this==t2){
            return true;
        }
        
        //判断两个对象的内容是否相同,相同返回true,不同返回false
        if(t2.b==this.b){
            return true;
        }else{
            return false;
        }
    }
}

public class Test {
    public static void main(String[] args) {

        //引用数据类型
        Test2 b1=new Test2(10);
        Test2 b2=new Test2(20);
        Test2 b3=new Test2(10);
        System.out.println(b1.equals(b2));//输出结果:false
        System.out.println(b1.equals(b3));//输出结果:true
    }
}

4. 面试题_谈谈重载与重写

对象英文名实现位置作用修饰符返回值类型方法名参数列表抛出异常类型方法体
重载overload同类中功能相同,提高效率无关无关相同不同无关不同
重写override子类中父类的方法无法满足子类的需求时权限大于等于等级小于等于相同相同等级小于等于不同

5. 组合

5.1 作用

组合顾名思义就是将多个对象组合到一个新对象,以实现更复杂强大的功能,提高代码复用性。

5.2 与继承的区别

当类之间的关系为“is”时,一般使用继承,比如:dog is animal,那么dog类可以继承animal类
当类之间的关系为“has”时,一般使用组合,比如:computer has cpu、memory、mainboard、screen… 那么computer类可以由cpu类、memory类、mainboard类等组合而成

5.3 实现方式

//CPU类
class Cpu{
    String cBrand;//cpu品牌
    public Cpu(){}//无参构造方法
    //有参构造方法
    public Cpu(String cBrand){
        this.cBrand=cBrand;
    }
}

//memory类
class Memory{
    String mBrand;//内存品牌
    public Memory(){}//无参构造方法
    //有参构造方法
    public Memory(String mBrand){
        this.mBrand=mBrand;
    }
}

//mainboard类
class Mainboard{
    String mbBrand;//主板品牌
    public Mainboard(){}//无参构造方法
    //有参构造方法
    public Mainboard(String mbBrand){
        this.mbBrand=mbBrand;
    }
}

//computer类
class Computer{
    Cpu cpu=new Cpu();//电脑的cpu
    Memory memory=new Memory();//电脑的内存
    Mainboard mainboard=new Mainboard();//电脑的主板
    public Computer(){}//无参构造方法
    //有参构造方法
    public Computer(String cBrand, String mBrand, String mbBrand){
        cpu.cBrand=cBrand;
        memory.mBrand=mBrand;
        mainboard.mbBrand=mbBrand;
    }
    //展示电脑的配置
    public void show(){
        System.out.println("My computer configuration:\nCPU:"+cpu.cBrand+"\nMemory: "+memory.mBrand+"\nMainboard: "+mainboard.mbBrand);
    }
}

public class Test {
    public static void main(String[] args) {
        Computer computer=new Computer("Inter","Samsung","MSI");
        computer.show();
    }
}
/*------------------------
输出结果:
My computer configuration:
CPU:Inter
Memory: Samsung
Mainboard: MSI
--------------------------*/

6. 多态

多态是同一个行为具有多个不同表现形式或形态的能力。

6.1 作用

减少重载方法数量,增强可扩充性及可替换性,降低耦合度

6.2 实现方式

  1. 存在继承关系
  2. 子类重写父类方法
  3. 将子类的对象赋给父类的引用变量
//父类
class Father{
    public void test(){
        System.out.println("父类");
    }
    public void show(Father f){
        f.test();
    }
}

//子类1
class Child1 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类1");
    }
}

//子类2
class Child2 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类2");
    }
}

//子类3
class Child3 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类3");
    }
}

public class Test {
    public static void main(String[] args) {
        Father f1=new Father();
        f1.show(new Child1());//实现多态  输出结果:子类1
    }
}

6.3 使用场景

  1. 使用父类作为方法的形参,实参可以是任意子类。示例代码如6.2示例代码
  2. 使用父类作为方法的返回值类型,实际返回的可以使任意子类的对象。示例代码如下:
//父类
class Father{
    public void test(){
        System.out.println("父类");
    }
    public Father show(){
        test();
        return new Father();
    }
}

//子类1
class Child1 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类1");
    }
}

//子类2
class Child2 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类2");
    }
}

//子类3
class Child3 extends Father{
    //重写父类方法
    public void test(){
        System.out.println("子类3");
    }
}

public class Test {
    public static void main(String[] args) {
        Child1 c1=new Child1();
        c1.show();//实现多态  输出结果:子类1
    }
}

7. 向上转型

  1. 基本数据类型自动转换,优先级:byte、char、short—>int—>long—>float—>double
  2. 引用数据类型自动转换,但转换后的父类引用对象不能访问子类特有的属性及方法
//父类
class Father{
    //父类的属性
    String fname="我是父类的属性";
    //父类的方法
    public void ftest(){
        System.out.println("我是父类的方法");
    }
}

//子类
class Child extends Father{
    //子类的属性
    String cname="我是子类自己的属性";
    //子类继承的方法(重写了)
    public void ftest(){
        System.out.println("我是子类重写父类的方法");
    }
    //子类自己的方法
    public void ctest(){
        System.out.println("我是子类自己的方法");
    }
}

public class Test {
    public static void main(String[] args) {
        //基本数据类型向上转型
        int a1=10;
        double a2=a1;//int型数据自动转换成double型数据
        System.out.println(a2);//输出结果:10.0

        //引用数据类型向上转型
        Father f=new Child();//子类自动转换成父类
        System.out.println(f.fname);//输出结果:我是父类的属性
        //System.out.println(f.cname);//报错,无法访问
        f.ftest();//输出结果:我是子类重写父类的方法
        //f.ctest();//报错,无法访问
    }
}

8. 向下转型

  1. 基本数据类型需要使用(type)进行强制转换
  2. 引用数据类型向下转型之前必须先向上转型,而且向上转型的子类是必须是之后向下转型的子类
//父类
class Father{

}

//子类1
class Child1 extends Father{

}

//子类2
class Child2 extends Father{

}

public class Test {
    public static void main(String[] args) {
        //基本数据类型向下转型
        double a1=10.52;
        int a2=(int)a1;//int型数据自动转换成double型数据
        System.out.println(a2);//输出结果:10

        //引用数据类型向下转型
        //Child c=(Child) new Father();//报错,java.lang.ClassCastException: class cn.khue.csdn.Father cannot be cast to class cn.khue.csdn.Child (cn.khue.csdn.Father and cn.khue.csdn.Child are in unnamed module of loader 'app')at cn.khue.csdn.Test.main(Test.java:42)
        //因为子类的向下转型必须先要向上转型
        Father f1=new Child1();//先向上转型
        Child1 c1=(Child1)f1;//再向下转型

        Father f2=new Child2();//先向上转型
        Child1 c2=(Child1)f2;//再向下转型,报错:java.lang.ClassCastException: class cn.khue.csdn.Child2 cannot be cast to class cn.khue.csdn.Child1 (cn.khue.csdn.Child2 and cn.khue.csdn.Child1 are in unnamed module of loader 'app')at cn.khue.csdn.Test.main(Test.java:38)
        //因为之前的向上转型的子类必须与之后向下转型的子类一样才行
    }
}

当然,为了提高效率,我们可以在向下转型之前使用instanceof进行判断

//父类
class Father{

}

//子类1
class Child1 extends Father{

}

//子类2
class Child2 extends Father{

}

public class Test {
    public static void main(String[] args) {
        //基本数据类型向下转型
        double a1=10.52;
        int a2=(int)a1;//int型数据自动转换成double型数据
        System.out.println(a2);//输出结果:10

        //引用数据类型向下转型
        Father f1=new Child1();
        Father f2=new Child2();
        //父类引用变量类型判断
        System.out.println(f1 instanceof Child1);//输出结果:true
        System.out.println(f1 instanceof Child2);//输出结果:false
        System.out.println(f1 instanceof Father);//输出结果:true
        System.out.println(f2 instanceof Father);//输出结果:true
        System.out.println(f1 instanceof Object);//输出结果:true
        System.out.println(f2 instanceof Object);//输出结果:true
        System.out.println(f1 instanceof Scanner);//报错,因为instanceof右侧的类只能是与左侧对象有继承关系才行
    }
}

9. 简单工厂模式

简单工厂模式也叫静态工厂方法

9.1 作用

不同new关键字,而通过一个静态方法来对外提供一个自身实例(对象)

9.2 实现方式

//父类
class Father{
    //简单工厂模式
    public static Father sFactoryM(String type){
        switch (type){
            case "c1":
                return new Child1();
            case "c2":
                return new Child2();
            default:
                return new Father();
        }
    }
}

//子类1
class Child1 extends Father{

}

//子类2
class Child2 extends Father{

}

public class Test {
    public static void main(String[] args) {
        //通过new关键字创建对象
        Father f1=new Father();
        //通过静态工厂方法创建对象
        Father f2=Father.sFactoryM("");
    }
}

10. final关键字

final是finally的意思,即最后的、最终的、不再变化的意思

10.1 修饰对象

对象final效果
可以修饰该类不能创建子类
方法可以修饰该方法不能被子类重写
变量可以修饰该变量成为常量,初始化后其值不能被修改
构造方法无法修饰
代码块无法修饰

注:

  1. final如果修饰的引用数据类型的变量,那么该变量所指向的对象的变量的值仍可以被改变,而该变量所指定的对象的地址值无法被修改。
  2. 虽然构造方法不能用final修饰,但我们可以使用关键字private修饰构造方法,来实现外部只能通过类名来访问该类的方法或变量(但内部类还是可以访问该类的构造方法的)。

10.2 常用的final实例

10.2.1 常用的final类

10.2.2 常用的final方法

10.2.3 常用的final变量

11. abstract关键字

abstract是抽象的意思,在Java中,抽象在某种意义上可以理解为不能被实例化

11.1 修饰对象

对象final效果
可以修饰(抽象类)该类无法创建对象(实例)
方法可以修饰(抽象方法)强制子类implements(实现)该方法或强制修改子类为抽象类
变量无法修饰
构造方法无法修饰
代码块无法修饰

注:

  1. 虽然抽象类自身无法创建对象,但可以通过子类的向上转型创建其对象,且抽象类存在构造方法供其子类访问。
  2. 抽象类最少一个抽象方法也没有,最多其内部方法都为抽象方法(除构造方法外)。
  3. 父类的方法是抽象的,子类的方法需要implements(实现)该方法,父类的方法不是抽象的,子类的方法可以override(重写)该方法。
  4. 包含抽象方法的类必须是抽象类,因为如果是非抽象类,那么该类便可以实例化,而实例化之后便可以访问该类的抽象方法,但抽象方法在本类中并没有方法体,必须让子类实现,所以,该类必须是抽象类。

11.2 常用的abstract实例

11.2.1 常用的抽象类

11.2.2 常用的抽象方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值