JavaSE学习总结(五)——封装,继承,多态很简单

java面向对象的三大特性是:封装、继承与多态,是面向对象编程的核心。java

1、封装

简单说封装就是将同一类事物的特性与功能包装在一块儿,对外暴露调用的接口。面试

封装:封装也称信息隐藏,是指利用抽象数据类型把数据和基于数据的操做封装起来,使其成为一个不可分割的总体,数据隐藏在抽象数据内部,尽量的隐藏数据细节,只保留一些接口使其与外界发生联系。也就是说用户无需知道内部的数据和方法的具体实现细节,只需根据留在外部的接口进行操做就行。编程

封装的好处:ide

1) 实现了专业的分工测试

2) 良好的封装可以减小耦合this

3) 类内部的结构可以自由修改spa

4) 能够对成员进行更精确的控制3d

5) 隐藏信息,实现细节调试

1.一、为何须要封装

定义一个学生类,在类中定义学生身高。code

Student类:

package com.zhangguo.c41;

/**学生类*/
public class Student {
    /**身高*/
    public int height;
    
    /**展现*/
    public void show(){
        System.out.println("身高:"+this.height+"cm");
    }
}

School类型:

package com.zhangguo.c41;

public class School {

    public static void main(String[] args) {
        
        Student tom=new Student();
        tom.height=189;
        tom.show();
        
        Student rose=new Student();
        rose.height=-398;
        rose.show();
    }

}

运行结果:

从示例中能够看出rose这个学生的对象的身高达-398cm这明显不科学,将属性封装起来,对外提供访问接口。

1.二、封装属性

若是要保护height这个属性,能够将它的访问修饰符修改成私有的,以下所示:

    /**身高*/
    private int height;

报错了:

由于是私有的,只有本类能够正常访问,外部访问不了,能够定义属性达到访问控制与封装的功能,以下所示:

Student类

package com.zhangguo.c41;

/** 学生类 */
public class Student {
    /** 身高 */
    private int height;

    /** 返回身高属性 */
    public int getHeight() {
        return this.height;
    }

    /**
     * 设置身高属性
     * 
     * @throws Exception
     */
    public void setHeight(int height) {
        // 若是参数height大于260或小于0
        if (height < 0 || height > 260) {
            // 输出错误信息
            System.out.println("身高只能是0-260之间");
        } else {
            this.height = height;
        }
    }

    /** 展现 */
    public void show() {
        System.out.println("身高:" + this.height + "cm");
    }
}

学生类:

package com.zhangguo.c41;

public class School {

    public static void main(String[] args) {
        
        Student tom=new Student();
        tom.setHeight(189);
        tom.show();
        
        Student rose=new Student();
        rose.setHeight(-398);
        rose.show();
    }

}

运行结果:

getXXX()得到,setXX(参数)设置

能够调试查看。

1.三、自动封装属性

若是在一个类中定义了很是多的属性,手动封装是很麻烦的,1个属性对应2个方法,1个get,1个set。Eclipse中有自动封装属性的功能,以下所示:

1.3.一、建立单个

将鼠标悬停在属性上,点击“create getter and setter for xxx”

1.3.二、批量建立

生成的结果:

package com.zhangguo.c41;

/***/
public class Dog {
    /**名称*/
    private String name;
    /**价格*/
    private float price;
    /**颜色*/
    private String color;
    
    //可读可写
    public float getPrice() {
        return price;
    }
    public void setPrice(float price) {
        this.price = price;
    }
    //只读
    public String getName() {
        return name;
    }
    //只写
    public void setColor(String color) {
        this.color = color;
    }
    
}

2、继承

2.一、 Java继承概要

Java继承是面向对象的最显著的一个特征。继承是从已有的类中派生出新的类,新的类能吸取已有类的数据属性和行为,并能扩展新的能力。JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个父类,易于管理程序,父类是子类的通常化,子类是父类的特殊化(具体化)

父类(基类):人   子类(派生):学生

学生继承人,人派生出学生

继承所表达的就是一种对象类之间的相交关系,它使得某类对象能够继承另一类对象的数据成员和成员方法。若类B继承类A,则属于B的对象便具备类A的所有或部分性质(数据属性)和功能(操做),咱们称被继承的类A为基类、父类或超类,而称继承类B为A的派生类或子类。

继承避免了对通常类和特殊类之间共同特征进行的重复描述。同时,经过继承能够清晰地表达每一项共同特征所适应的概念范围——在通常类中定义的属性和操做适应于这个类自己以及它如下的每一层特殊类的所有对象。运用继承原则使得系统模型比较简练也比较清晰。

java使用extends关键字标识继承。

2.二、为何须要继承

Dog狗

package com.zhangguo.c42;

/***/
public class Dog {
    /**名称*/
    public String name;
    /**颜色*/
    public String color;
    /**价格*/
    public double price;
    
    /**显示信息*/
    public void show(){
        System.out.println("名称:"+name+",颜色:"+color);
    }
}

Cat猫

package com.zhangguo.c42;

/***/
public class Cat {
    /**名称*/
    public String name;
    /**颜色*/
    public String color;
    /**重量*/
    public double weight;
    
    /**显示信息*/
    public void show(){
        System.out.println("名称:"+name+",颜色:"+color);
    }
}

Zoo动物园

package com.zhangguo.c42;

/**动物园*/
public class Zoo {

    public static void main(String[] args) {
        Dog dog=new Dog();
        dog.name="吉娃娃狗";
        dog.color="绿色";
        dog.price=19800.7;
        dog.show();
        
        Cat cat=new Cat();
        cat.name="波斯猫";
        cat.color="红色";
        cat.weight=18.5;
        cat.show();
        
    }

}

运行结果:

上面的代码实现了基本功能,但有问题,主要是:name,color,show重复,若是系统中的动物类再增长将不停的重复,重复就会带来不便修改,不便维护的问题。

2.三、实现继承

要解决上面的问题可使用继承,达到代码复用的目的。

Animal动物:

package com.zhangguo.c43;

/**动物*/
public class Animal {
    /**名称*/
    public String name;
    /**颜色*/
    public String color;
    
    /**显示信息*/
    public void show(){
        System.out.println("名称:"+name+",颜色:"+color);
    }
}

Dog狗:

package com.zhangguo.c43;

/**狗继承自动物,子类 is a 父类*/
public class Dog extends Animal {
    /**价格*/
    public double price;
}

Cat猫:

package com.zhangguo.c43;

/***/
public class Cat extends Animal {
    /**重量*/
    public double weight;
}

Zoo动物园:

package com.zhangguo.c43;

/**动物园*/
public class Zoo {

    public static void main(String[] args) {
        Dog dog=new Dog();
        dog.name="吉娃娃狗";
        dog.color="绿色";
        dog.price=19800.7;
        dog.show();
        
        Cat cat=new Cat();
        cat.name="波斯猫";
        cat.color="红色";
        cat.weight=18.5;
        cat.show();
        
    }

}

运行结果:

从示例中可见dog并无定义color属性,但在使用中能够调用,是由于dog继承了父类Animal,父类的非私有成员将被子类继承。若是再定义其它的动物类则无须再反复定义name,color与show方法。

2.2. Java继承的特征

2.2.一、传递性

若类C继承类B,类B继承类A(多继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还能够有本身新定义的属性和方法。继承来的属性和方法尽管是隐式的,但还是类C的属性和方法。

2.2.二、单根性

若类B继承类A,那么创建类B时只须要再描述与基类(类A)不一样的少许特征(数据成员和成员方法)便可。这种作法能减少代码和数据的冗余度,大大增长程序的重用性。

2.2.三、子类调用父类成员

一、使用super关键字调用父类成员

二、子类默认会先调用父类的无参构造方法,若是父没有则报错,能够手动指定,但必须在第一行

动物:

package com.zhangguo.c43;

/**动物*/
public class Animal {
    /**名称*/
    public String name;
    /**颜色*/
    public String color;
    
    public Animal() {
        System.out.println("这是动物类的空构造方法");
    }
    
    public Animal(String name, String color) {
        this.name = name;
        this.color = color;
    }

    /**显示信息*/
    public void show(){
        System.out.println("名称:"+name+",颜色:"+color);
    }
}

狗:

package com.zhangguo.c43;

/**狗继承自动物,子类 is a 父类*/
public class Dog extends Animal {
    public Dog(String name, String color,double price) {
        super(name,color);  //调用父类构造方法
        this.price=price;  //调用当前对象的成员
    }
    
    /**价格*/
    public double price;
    
    /**重写父类方法*/
    public void show(){
        /**子类调用父类成员*/
        super.show();
        System.out.println("价格:"+this.price);
    }
}

猫:

package com.zhangguo.c43;

/***/
public class Cat extends Animal {
    /**重量*/
    public double weight;
}

动物园:

 

package com.zhangguo.c43;

public class Zoo {

    public static void main(String[] args) {
        
        Dog dog = new Dog("中华田园犬","蓝色",123.56);
        dog.show();

        Cat cat = new Cat();
        cat.name = "波斯猫";
        cat.color = "红色";
        cat.weight = 18.5;
        cat.show();

        A a = new A();
        a.y = 100;
        B b = new B();
        b.y = 200;
        // com.nf.c401.Hello h=new com.nf.c401.Hello();

        C c = new C();
        c.y = 200;
        c.z = 200;

    }
}

class A {
    /**
     * private 私有的,只容许本类访问 
     * public 公有的,容许全部类访问 
     * protected 授权保护的,只容许子类访问,同包访问
     * default 容许同一个包访问 package,不写访问修饰符
     **/
    private int x;
    protected int y;
}

class B extends A {
    public int z;
}

class C extends B {
}


//class D extends A,B,C{}  单根性,只能继承一个父类,可实现多个接口

运行结果:

3、构造方法

 3.一、构造方法概要

a)、构造方法是建立对象时调用的方法,(实例化,new),析构方法

b)、构造方法名与类名相同(如Book类的构造方法名称必定Book)

c)、构造方法没有返回类型() public Book(){}

d)、一个类若是不定义构造方法会默认有一个无参构造方法,若是用户自定义了构造方法则再也不默认定义无参构造方法

package com.zhangguo.c44;

/***/
public class Car {
    
    /**车速*/
    private int speed;
    
    //构造方法
    public Car() {
        System.out.println("安装轮胎");
        System.out.println("安装方向盘");
        this.speed=230;
    }
    
}

测试

package com.zhangguo.c44;

public class CarClient
{
    public static void main(String[] args) {
        
        
        Car c1=new Car();
        
        Car c2=new Car();
        
    }
}

结果:

3.二、带参数的构造方法

a)、构造方法的参数与普通方法相同

b)、构造方法容许重载(同名方法不一样参数个数或类型)

c)、在建立子类时会默认调用父类的构造方法,通常是无参构造

d)、使用super能够调用父类指定的构造方法,子类中调用父类的构造方法时必须在第一行

e)、使用super能够调用父类中的任意公开成员

package com.zhangguo.c44;

/***/
public class Car {
    
    /**车速*/
    public int speed;
    
    //构造方法
    public Car(int _speed) {
        this.speed=_speed;
    }
    
    //无参构造方法
    public Car(){
        this.speed=100;
    }
    
    /**启动*/
    public void start()
    {
        System.out.println("车速:"+this.speed);
    }
    
}

测试:

package com.zhangguo.c44;

public class CarClient
{
    public static void main(String[] args) {
        
        
        Car c1=new Car(99);
        c1.speed=100;
        c1.start();
        
        Car c2=new Car(350);
        c2.start();
        
        Car c3=new Car();
        c3.speed=198;
        c3.start();
        
    }
}

结果:

package com.zhangguo.c44;

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

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


public class Student {

    public static void main(String[] args) {
        B b=new B();

    }

}

运行结果:

A

B

动物:

package com.zhangguo.c47;

/**动物*/
public class Animal {
    
    public Animal() {
    }
    
    public Animal(String name){
        setName(name);
    }
    
    /**名称属性*/
    private String name;
    /**
     * 得到名称
     */
    public String getName() {
        return name;
    }
    /**
     * 设置名称
     */
    public void setName(String name) {
        this.name = name;
    }
    
    /**展现*/
    public void show(){
        System.out.println("这是"+this.name);
    }
    
    
    
}

狗:

package com.zhangguo.c47;

/***/
public class Dog extends Animal {
    public Dog() {
    }
    public Dog(String name,String color) {
        super(name);
        setColor(color);
    }
    
    /**颜色*/
    private String color;
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }
    
    /**重写父类的show方法,由于父类中也有同样的show方法*/
    public void show(){
        super.show();
        System.out.println(" 颜色:"+color);
    }
    
    //注解
    @Override
    public String toString() {
        return "名称:"+getName()+",颜色:"+getColor();
    }
    
    
}

动物园:

package com.zhangguo.c47;

public class Zoo {

    public static void main(String[] args) {
        Dog dog1=new Dog("吉娃娃","红色");
        System.out.println(dog1.toString());
        
        Dog dog2=new Dog("大娃娃","蓝色");
        System.out.println(dog2.toString());
    }

}

结果:

4、多态

面向对象的多态性主要体如今:重写重载两方面,前面的课程中已经详细讲解太重载。

4.0、重载

同名方法,不一样参数(类型或个数),与返回值无关,适用全部方法(构造,静态,实例)。

构造方法重载:

package com.nf.c401;

/** 学生 类 */
public class Student {
    /** 构造方法 */
    public Student(int height, String name, String hobby) {
        // super(); /**调用父类构造方法,写在第一行,默认就调用*/
        this.height = height;
        this.name = name;
        this.hobby = hobby;
    }

    public Student(int height, String name) {
        this.height = height;
        this.name = name;
    }

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

    public Student() {
    }

    /** 身高 字段,成员变量,全部成员变量都有默认值 */
    private int height;

    /** 姓名 */
    private String name;
    /** 爱好 */
    private String hobby;

    /** 身高属性,写 */
    public void setHeight(int height) {

        if (height > 0 && height < 300) {
            this.height = height;
        } else {
            System.out.println("身高不正确");
        }
    }

    /** 身高属性 读 */
    public int getHeight() {
        return this.height;
    }

    /** 显示 方法 */
    public void show() {
        System.out.println("身高:" + height + ",姓名:" + this.name + ",爱好:" + hobby);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

}

测试类:

package com.nf.c401;

public class School {
    public static void main(String[] args) {
        Student tom=new Student(171,"张果","代码");
        tom.show();
        
        Student rose=new Student();
        rose.show();
        
        Student mark=new Student("马克");
        mark.setHeight(158);
        mark.setHobby("篮球");
        mark.show();
    }
}

结果:

自动封装:

普通方法重载:

系统重载方法:

        /**java内置的方法,有不少重载*/
        System.out.println("重载");
        System.out.println(98.5);
        System.out.println(true);

自定义重载方法:

package com.nf.c401;

public class Math {
    
    public void add(int a,int b){
        System.out.println(a+"+"+b+"="+(a+b));
    }
    /**参数个数不一样*/
    public int add(int a,int b,int c){
        System.out.println(a+"+"+b+"+"+c+"="+(a+b+c));
        return a+b;
    }
    /**参数类型不一样*/
    public void add(double a,double b){
        System.out.println(a+"+"+b+"="+(a+b));
    }
}

测试:

package com.nf.c401;

public class MathTest {
    public static void main(String[] args) {
        Math math=new Math();
        math.add(10, 15);
        math.add(1.0, 1.5);
        math.add(100, 200,10);
    }
}

输出结果:

4.一、LSP(里氏代换原则)

LSP全称Liskov Substitution Principle,中文名意思是里氏代换原则。LSP讲的是基类和子类的关系。只有当这种关系存在时,里氏代换关系才存在。

子类必定能够替换父类。

子类的信息量必定大于父类的。老鼠的儿子会打洞,老鼠的儿子必定能够替代老鼠的父亲

package com.zhangguo.c45;

class A{
}
class B extends A{
}

public class Student {
    public static void main(String[] args) {
        A a1=new B();
        Object a2=new A();
        
        task(new B());
    }
    
    public static void task(A a){
        
    }

}

在代码中须要父类对象的地方均可以使用子类对象替换。

4.二、重写(override)

 在Java中,子类可继承父类中的方法,而不须要从新编写相同的方法。但有时子类并不想原封不动地继承父类的方法,而是想做必定的修改,这就须要采用方法的重写。方法重写又称方法覆盖。

package com.zhangguo.c46;

class Car{
    public void start()
    {
        System.out.println("车在跑");
    }
}

class SuperCar extends Car{
    public void start()
    {
        System.out.println("车在飞");
    }
}

public class Student {
    public static void main(String[] args) {
        Car car=new SuperCar();
        car.start();
    }
}

运行结果:

车在飞

4.三、多态实现

同一个类的不一样子类对象对同一个方法的调用产生不一样的结果叫多态

演员

厨师

理发师

他都是Person人的子类,但当听到Cut(切)时他们的表现不同。

 

package com.zhangguo.c47;

/***/
public class Person {
    
    public void cut(){
    }
    
    public static void main(String[] args) {
        Person player=new Player();
        Person cooker=new Cooker();
        Person cuter=new Cuter();
        
        player.cut();
        cooker.cut();
        cuter.cut();
    }
}

/**演员*/
class Player extends Person
{
    /**重写*/
    public void cut(){
        System.out.println("中止演戏");
    }
}

/**厨师*/
class Cooker extends Person
{
    /**重写*/
    public void cut(){
        System.out.println("开始切菜");
    }
}

/**厨师*/
class Cuter extends Person
{
    /**重写*/
    public void cut(){
        System.out.println("开始剪头发");
    }
}

运行结果:

程序中定义的引用变量所指向的具体类型和经过该引用变量发出的方法调用在编程时并不肯定,而是在程序运行期间才肯定,即一个引用变量倒底会指向哪一个类的实例对象,该引用变量发出的方法调用究竟是哪一个类中实现的方法,必须在由程序运行期间才能决定。由于在程序运行时才肯定具体的类,这样,不用修改源程序代码,就可让引用变量绑定到各类不一样的类实现上,从而致使该引用调用的具体方法随之改变,即不修改程序代码就能够改变程序运行时所绑定的具体代码,让程序能够选择多个运行状态,这就是多态性。多态性加强了软件的灵活性和扩展性。小李喜欢听小鸟唱歌{麻雀,杜鹃,鹦鹉}

    小李:窗外的鸟儿,给我唱首歌。

    1.(鸟 bird = new 麻雀 )?

    2.(鸟 bird = new 杜鹃 )?

    3.(鸟 bird = new 鹦鹉 )?

    鸟儿:bird.sing()~~~~~

    小李:鸟儿唱的不错,你是哪一种鸟?

    鸟儿: bird.shape()

    小李:(---若是上面蓝字定义的是3,是鹦鹉)哈哈!原来你是鹦鹉!

    因此,多态的过程实质是一个抽象指令,让一组具备相同行为单具备不一样内容的个体协同工做的这样的一个过程。

方法的重写、重载与动态链接构成多态性;

  Java之因此引入多态的概念,缘由之一是它在类的继承问题上和C++不一样,后者容许多继承,这确实给其带来的很是强大的功能,可是复杂的继承关系也给C++开发者带来了更大的麻烦,为了规避风险,Java只容许单继承,派生类与基类间有IS-A的关系(即“猫”is a “动物”)。这样作虽然保证了继承关系的简单明了,可是势必在功能上有很大的限制,因此,Java引入了多态性的概念以弥补这点的不足,此外,抽象类和接口也是解决单继承规定限制的重要手段。同时,多态也是面向对象编程的精髓所在。

  要理解多态性,首先要知道什么是“向上转型”。

  我定义了一个子类Cat,它继承了Animal类,那么后者就是前者的父类。我能够经过

  Cat c = new Cat(); 例化一个Cat的对象,这个不难理解。

  但当我这样定义时: Animal a = new Cat();

  这表明什么意思呢?

  很简单,它表示我定义了一个Animal类型的引用,指向新建的Cat类型的对象。因为Cat是继承自它的父类Animal,因此Animal类型的引用是能够指向Cat类型的对象的。那么这样作有什么意义呢?由于子类是对父类的一个改进和扩充,因此通常子类在功能上较父类更强大,属性较父类更独特,定义一个父类类型的引用指向一个子类的对象既可使用子类强大的功能,又能够抽取父类的共性。因此,

  父类引用只能调用父类中存在的方法和属性,不能调用子类的扩展部分;由于父类引用指向的是堆中子类对象继承的父类;(可是若是强制把超类转换成子类的话,就能够调用子类中新添加而超类没有的方法了。)

  同时,父类中的一个方法只有在父类中定义而在子类中没有重写的状况下,才能够被父类类型的引用调用;

  对于父类中定义的方法,若是子类中重写了该方法,那么父类类型的引用将会调用子类中的这个方法,这就是动态链接。

5、示例与视频下载

6、面试题

一、定义包使用什么关键字?

package com.zhangguo.projectA

二、导入包使用什么关键字?

import com.zhangguo.projectA.类    import com.zhangguo.projectA.*

三、若是想导入com.zhangguo.project下的全部类应该怎样声明?

import com.zhangguo.project.*

四、静态方法是否能够直接调用同一个类中其它非静态方法?
不行,经过对象调用

五、非静态方法是否能够直接调用同一个类中的其它静态方法?

同一个类:直接调用

不一样的类:使用类名调用,如类名.成员名

package com.gdnf.java.d3;

public class Student {

    public static void main(String[] args) {
        //静态的直接调用静态的
        int i=add(1,2);
        System.out.println(add(add(i,100),7));
        
        //静态的实例调用非静态的  ***
        Student stu=new Student();
        System.out.println(stu.calc(1,2,add(9,91)));
    }
    
    public int calc(int i,int j,int k){
        //非静态的直接调用静态的
        return  add(add(i,j),k);
    }
    
    /**
     * 加法操做
     * @param x 第一个参数
     * @param y 第二个参数
     * @return 相加的结果
     */
    public static int add(int x,int y){
        return x+y;
    }

}

运行结果:

六、请定义一个类车(Car),在车中定义属性车速(Speed)与车名(Name),封装Speed与Name,要求车速在50-300之间;定义Start方法输出车名与车速。测试定义好的类TestCar;

 

七、请定义父类人(Person),属性姓名(Name)与性别(Sex),方法Hello方法输出姓名与性别;子类学生Student与老师Teacher分别继承人,

Student拥有属性班级(ClassNO),老师拥有属性教龄(TeachLen);测试定义好的类TestSchool;

 

八、java面向对象的三大特性是:封装、继承与多态

 

九、有一个类的定义是这样的:public class Cat extends Animal,其中Cat是猫,Animal是动物,请问基类是、子类是、基类又称为何?子类又称为何?

基类Animal、子类Cat 、基类又称为父类,子类又称为派生类

十、已知以下类(Phone:Product,Book:Product),请完成另外一个类(Book,添加属性Author)的继承,请实现对Price的封装

Product.java

package com.zhangguo.c44;

/** 产品 */
public class Product {
    /** 价格 */
    private double price;

    /** 得到价格 */
    public double getPrice() {
        return price;
    }

    /** 设置价格 */
    public void setPrice(double price) {
        if (price >= 0) {
            this.price = price;
        } else {
            System.out.println("价格必须>=0");
        }
    }

    /** 展现 */
    public void show() {
        System.out.println("商品的价格是:" + price);
    }
}

Book.java

package com.zhangguo.c44;

/** 图书 继承 产品 */
public class Book extends Product {
    /** 做者 属性 */
    private String author;
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

Phone.java

package com.zhangguo.c44;

/**电话*/
public class Phone extends Product {
    /**品牌*/
    public String brand;
}

class Vivo extends Phone
{
    
}

Store.java

package com.zhangguo.c44;

public class Store {

    public static void main(String[] args) {
        //请定义图书对象,设置价格为-100,显示价格
        Book book = new Book();
        book.setPrice(-100);
        book.show();
        
        Vivo vivo=new Vivo();
        
        
    }

}

 

相关文章
相关标签/搜索