一、Java面试基础之面向对象的特征:继承、封装和多态(原创实例)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/QQB67G8COM/article/details/81428660

一、继承

1、概念:继承是类与类的一种关系,是一种“is a”的关系。比如“狗”继承“动物”,这里动物类是狗类的父类或者基类,狗类是动物类的子类或者派生类。

2、java中的继承是单继承,即一个类只有一个父类

3、优点:子类拥有父类的所有属性和方法(除了private修饰的属性不能拥有)从而实现了实现代码的复用

4、语法规则,只要在子类加上extends关键字继承相应的父类就可以了
class 子类 extends 父类
栗子:class Dog extends Animal{……}

5、方法的重写:子类不满意父类的方法时,可以编写自己的继承方法,这种方式称为方法的重写,并用@override注解来标注该方法为重写方法,该注解带有识别功能,能辨识你的方法是否为重写方法,否则在编译阶段就会报错
重载和重写的区别:

方法重载:在同一个类中处理不同数据的多个相同方法名的多态手段。
方法重写:相对继承而言,子类中对父类已经存在的方法进行区别化的修改。

6、final关键字
final有“最终的”含义:

1)final 修饰类,则该类不允许被继承
2)final 修饰方法,则该方法不允许被覆盖(重写)
3)final 修饰属性,则该类的该属性不会进行隐式的初始化,所以 该final 属性的初始化属性必须有值,或在构造方法中赋值(但只能选其一,且必须选其一,因为没有默认值!),且初始化之后就不能改了,只能赋值一次
4)final 修饰变量,则该变量的值只能赋一次值,在声明变量的时候才能赋值,即变为常量
7、super关键字
在对象的内部使用可代表父类对象
1)访问父类属性:super.fatherProperty
2)访问父类方法:super.fatherMethod()
super的应用:
1)首先我们知道子类的构造的过程当中必须调用父类的构造方法。其实这个过程已经隐式地使用了我们的super关键字
2)这是因为如果子类的构造方法中没有显示调用父类的构造方法,则系统默认调用父类无参的构造方法。那么如果自己用super关键字在子类里调用父类的构造方法,则必须在子类的构造方法中的第一行
3)注意:如果子类构造方法中既没有显示调用父类的构造方法,而父类没有无参的构造方法,则编译出错。
4)如果父类没有显示声明父类的无参的构造方法,系统会自动生成一个无参构造方法,但是如果声明了一个有参构造方法而没有声明无参构造方法,这时系统不会自动默认生成一个无参构造方法,此时称为父类没有无参构造方法。
8、Object类
Object类是所有类的父类,如果一个类没有使用extends关键字明确标识继承另一个类,那么这个类默认继承Object类。
Object类中的方法,适合所有子类

二、封装

1、封装概念:
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
2、封装优点:
只能通过规定的方法访问数据。
隐藏类的实例细节,方便修改和实现。
3、封装的实现步骤
属性可见性设置为private–>创建用于读写的getter/setter方法–>在getter/setter方法中加入属性控制语句
4、注意:对封装的属性不一定要通过get/set方法,其他方法也可以对封装的属性进行操作。当然最好使用get/set方法,比较标准。

5、访问修饰符(访问权限最大范围)
private:本类
default:包内
protected:包内、子类
public:包内、子类、其它
6、this关键字
1)this关键字代表当前对象
   this.属性 操作当前对象的属性
   this.方法 调用当前对象的方法。
2)封装对象的属性的时候,经常会使用this关键字
3)当getter和setter函数参数名和成员函数名重合的时候,可以使用this区别
7、内部类
内部类( Inner Class )就是定义在另外一个类里面的类。与之对应,包含内部类的类被称为外部类。
内部类的主要作用:
1)内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
2)内部类的方法可以直接访问外部类的所有数据,包括私有的数据。
3)内部类所实现的功能使用外部类同样可以实现,只是有时使用内部类更方便。
内部类可分为以下几种: 
成员内部类
静态内部类
方法内部类
匿名内部类

三、多态

多态就是对象的多种形态,什么对象才会具有多种形态?原子性的事物没有多种形态,是什么就是什么,某一类事物,是概念上事物,不指

1、引用多态
父类的引用可以指向本类的对象,也可以指向子类的对象,反过来行不通。
简单理解下:猫狗和动物的关系,从属不能颠倒,但动物(父类)可作为一个引用指向猫或狗,因为猫狗都是动物。
引用的百度解释:引用是指在说话或写作中引用现成的话,如诗句.格言、成语等,以表达自己思想感情的修辞方法。引用可分为明引和暗引两种。明引指直接引用原文,并加上引号,或者是只引用原文大意,不加引号,但是都注明原文的出处。暗引指不说明引文出处,而将其编织在自已的话语中,或是引用原句,或是只引大意。运用引用辞格,既可使文章言简意赅,有助于说理抒情;又可增加文采,增强表现力。
简单粗暴的理解:挖掘机、推土机都是机械类,挖掘机属于机械类,机械可作为挖掘机的一个引用,挖掘机自己引用自己时就是挖掘机在工作,机械作为引用时是,机械在工作,实际上你还是台挖掘机,里面有挖掘机从机械里继承过来的属性方法以及重写机械的方法和重载自己的方法,得出一个结论就是外部看来,挖掘机选择了自己的种类名,类比到人,当人不喊人喊自己为动物的时候,我......
2.方法多态
创建本类对象调用的方法为本类方法,创建子类对象,调用的方法为子类重写的方法或者继承的方法。
父类只能调用子类继承父类的方法或者调用子类重写父类的方法,继承是多态的基础。
栗子:一颗苹果树(父亲)砍枝载种出另一棵苹果树(儿子),两棵树形似神不似,世上没有两棵完全相同的苹果树,这就是继承与发展(重写),放在程序上,你的方法都是继承我的并重写了,那么我应该也是会用的,都说推土机管你内部怎么改,只要功能不变我就会用,因为参数不变,返回值不变,父亲自然也是会用儿子重新修改过自己的方法的内部过程的方法,因为我不需要了解你怎么去整的,但是子苹果树嫁接了桃子木,菠萝枝,父亲一脸懵逼,因为这个是儿子的创造新东西,父亲完全不会啊,怎么调用(谁反过来说我跟谁没完)
3、引用类型转换
1) 向上类型转换(隐式/自动类型转换),是小类型转换到大类型
2) 向下类型转换(强制类型转换),是大类型转换到小类型(有风险,可能出现数据溢出)。
4、instanceof运算符,来解决引用对象的类型,避免类型转换的安全性问题
1)它的作用是测试它左边的对象是否是它右边的类的实例,返回boolean类型的数据
2)instanceof是Java的一个二元操作符,和==,>,<同类
3)强转时最好事先验证左对象是否为右对象的实例
5、抽象类(不完全抽象)
定义:抽象类前使用abstract关键字修饰,则该类为抽象类。
使用抽象类要注意以下几点:
1)抽象类是约束子类必须有什么方法,而并不关注子类如何实现这些方法。
2)抽象类应用场景:
   a. 在某些情况下,某个父类只是知道其子类应该包含怎样的方法,但无法准确知道这些子类如何实现这些方法(可实现动态多态)。
   b. 从多个具有相同特征的类中抽象出一个抽象类,以这个抽象类作为子类的模板,从而避免子类设计的随意性。
3)抽象类定义抽象方法,只有声明,不需要实现。抽象方法没有方法体以分号结束,抽象方法必须用abstract关键字来修饰。
4)包含抽象方法的类是抽象类。抽象类中可以包含普通的方法,也可以没有抽象方法。
6、接口(完全抽象)

1)接口的属性全部为常量
2)接口定义的基本语法

[修饰符] [abstract] interface 接口名 [extends父接口1,2....](多继承){
   0…n常量 (public static final)                                          
           0…n 抽象方法(public abstract)                                      
}    

其中[ ]里的内容表示可选项,可以写也可以不写;接口中的属性都是常量,即使定义时不添加public static final 修饰符,系统也会自动加上;接口中的方法都是抽象方法,即使定义时不添加public abstract修饰符,系统也会自动加上
3)使用接口
一个类可以实现一个或多个接口,实现接口使用implements关键字。java中一个类只能继承一个父类,是不够灵活的,通过实现多个接口可以补充
继承父类实现接口的语法为:
     
[修饰符] class 类名 extends 父类 implements 接口1,接口2…{
类体部分//如果继承了抽象类,需要实现继承的抽象方法;要实现接口中的抽象方法
}
4)如果要继承父类,继承父类必须在实现接口之前,即extends关键字必须在implements关键字前

7.抽象类和接口的区别

1)接口属于完全抽象类,只能包含抽象方法,抽象类可以包含普通方法
2)接口只能定义静态常量属性,抽象类可以定义静态常量属性也可以定义普通属性
3)类实现接口时也要实现接口中定义的方法,即使方法为空
4)接口没有构造方法,抽象类可以包含构造方法
5)接口直接定义 要做的事情(计划表),并没有 进行实现(执行计划)
6)抽象类不能被实例化,但其可以可以有构造函数,方便继承类进行扩充


以上并非原创,内容来自五湖四海的总结,以下为原创代码助你起飞


ISkill.java

package OO;

public interface ISkill {
    //固定技能属性,默认就是public static final
    int skillFixedValue_b = 10;
    static final int skillFixedValue_o = 13;
    public static final int skillFixedValue_m = 8;

    //定义技能,默认就是abstract
    public void broken();//釜底抽薪
    public abstract void oceanCart();//罗汉推车
    public abstract void monkeyPeache();//猴子偷桃

//  public ISkill(){}   //接口没有构造方法
}

SkillExpand.java

package OO;

/**
 * 抽象类实际上是个半抽象类,抽象类实现接口不用全部实现接口所定义的方法
 * 
 * @class OO.SkillExpand
 * @author ljj
 * @date 2018年8月5日
 * @notes
 *
 */
public abstract class SkillExpand implements ISkill {

    public SkillExpand() {
        System.out.println();
        System.out.println("触发SkillExpand抽象方法的无参构造函数");
    }

    /**
     * 定义抽象技能信息方法
     */
    public abstract void killInfo();

    /**
     * 实现ISkill中的broken()方法,引入ISkill的常量
     */
    @Override
    public void broken() {    
        System.out.println("释放技能  釜底抽薪,攻击力为:"+skillFixedValue_b);
    }
}

SkillRealize.java

package OO;

/**
 * 继承抽象类可以得到一个结论,SkillExpand抽象类已经实现ISkill
 * 接口的broken方法了,接口的其它的方法没有进行实现,因此在子类继承抽
 * 象类时需要实现 抽象类未能实现接口ISkill的其它方法。抽象类实现接口时,
 * 当不想实现接口的某些方法时,就将这些方法的实现抛给继承自己的子类(普通类)
 * ,还有在抽象类内部定义的抽象方法也会一起抛给普通子类去实现,但是如果所有的
 * 接口方法都在抽象类中实现了,那么继承自己的普通子类就不用去实现了,还可以直接
 * 调用.
 * 
 * @class OO.SkillRealize
 * @author ljj
 * @date 2018年8月5日
 * @notes
 *
 */
public class SkillRealize extends SkillExpand {

    public SkillRealize() {
        System.out.println(" 触发SkillRealize无参构造函数");
    }

    public SkillRealize(int a, int b) {
        System.out.println("SkillRealize有参构造函数,a="+ a +",b="+b);
    }

    @Override
    public void oceanCart() {
        System.out.println("释放罗汉推车技能,攻击力为:"+skillFixedValue_o);
    }

    @Override
    public void monkeyPeache() {
        System.out.println("释放猴子偷桃技能,攻击力为"+skillFixedValue_m);
    }

    @Override
    public void killInfo() {
        System.out.println("技能一览:");
        this.oceanCart();
        this.monkeyPeache();    //访问当前类对象的方法
        super.broken();         //super访问父类方法
    }

}

IWeapom.java

package OO;

public interface IWeapom {
    public void attack();//攻击方法
    public void AOE();//武器的大招
}

Pan.java

package OO;

public class Pan implements IWeapom {

    @Override
    public void attack() {
        System.out.println("平底锅攻击:吃鸡平底锅秒杀攻击");
    }

    @Override
    public void AOE() {
        System.out.println("平底锅觉醒:天降正义!!");
    }

}

Spear.java

package OO;

public class Spear implements IWeapom {

    @Override
    public void attack() {
        System.out.println("长枪攻击:连续突刺");
    }

    @Override
    public void AOE() {
        System.out.println("长枪觉醒:百步穿杨");
    }
}

Animal.java

package OO;

public class Animal {
    public Animal() {
        System.out.println("触发Animal构造函数");
    }

    public void eat() {
        System.out.println("动物吃饭");
    }

    public void run() {
        System.out.println("动物跑步");
    }
}

Father.java

package OO;

public class Father extends Animal {

    public Father() {
        System.out.println("Father无参构造函数");
        System.out.print("技能1");
        this.getSpear().attack();
        System.out.print("技能2");
        this.getSpear().AOE();
        System.out.print("怒气技能");
        this.getSr().oceanCart();
    }

    //对象组合
    private Spear spear;
    private SkillRealize sr;

    @Override           //父类方法重写
    public void eat(){
        System.out.println("Father在吃饭......");
        System.out.print("吃饭时父类看见");
        super.run();//直接调用父类的方法
    }

    //重载 重写父类的方法,听得懂?
    public void eat(String eatTool){
        System.out.println("Father用"+eatTool+"吃饭");
    }

    public Spear getSpear() {
        return new Spear();
    }

    public SkillRealize getSr() {
        return new SkillRealize();
    }
}

Mother.java

package OO;

public class Mother extends Animal {

    public Mother() {
        System.out.println("触发Mother无参构造函数:");
        System.out.print("技能1");
        this.getPan().attack();
        System.out.print("技能2");
        this.getPan().AOE();
        System.out.print("怒气技能");
        this.getSr().monkeyPeache();

    }

    //对象组合
    private Pan pan;
    private SkillRealize sr;

    @Override
    public void eat(){
        System.out.println("Mother在吃饭......");
    }

    public Pan getPan() {
        return new Pan();
    }

    public SkillRealize getSr() {
        return new SkillRealize(1, 2);
    }   
}

Test.java

package OO;

public class Test {
    public static void main(String[] args) {
        Father father = new Father();

        System.out.println("------华丽丽的分割线1------");
        Animal animal = new Mother();
        animal.eat();

        System.out.println("------华丽丽的分割线2------");
        Animal animal2 = father;//向上转型
        animal2.eat();

        System.out.println("------华丽丽的分割线3------");
        Father father2 = (Father) animal2;//向下转型,下转有风险,此处无风险,因为可以确定father2最终是引用father的,下转可能造成数据溢出
        father2.eat();

        System.out.println("------华丽丽的分割线4------");
        System.out.println(father instanceof Animal);
        System.out.println(animal instanceof Father);

        System.out.println("------华丽丽的分割线5------");
        new SkillRealize().killInfo();
    }
}

运行结果:

触发Animal构造函数
Father无参构造函数
技能1长枪攻击:连续突刺
技能2长枪觉醒:百步穿杨
怒气技能
触发SkillExpand抽象方法的无参构造函数
 触发SkillRealize无参构造函数
释放罗汉推车技能,攻击力为:13
------华丽丽的分割线1------
触发Animal构造函数
触发Mother无参构造函数:
技能1平底锅攻击:吃鸡平底锅秒杀攻击
技能2平底锅觉醒:天降正义!!
怒气技能
触发SkillExpand抽象方法的无参构造函数
SkillRealize有参构造函数,a=1,b=2
释放猴子偷桃技能,攻击力为8
Mother在吃饭......
------华丽丽的分割线2------
Father在吃饭......
吃饭时父类看见动物跑步
------华丽丽的分割线3------
Father在吃饭......
吃饭时父类看见动物跑步
------华丽丽的分割线4------
true
false

触发SkillExpand抽象方法的无参构造函数
 触发SkillRealize无参构造函数
技能一览:
释放罗汉推车技能,攻击力为:13
释放猴子偷桃技能,攻击力为8
释放技能  釜底抽薪,攻击力为:10

有啥问题欢迎指出,共同学习—-最强王者小学生


猜你喜欢

转载自blog.csdn.net/QQB67G8COM/article/details/81428660
今日推荐