Java面向对象(三):封装,继承与多态

面向对象三大特征:封装,继承,多态

1.封装 ->封装的核心思想是权限控制,目的是信息保护
当类和类内部的成员被定义好后,基于安全性考虑可能并不希望把所有成员都暴露给外部调用,于是通过权限修饰符控制使得外部无法直接使用部分成员,这个过程就是封装。
public class Oop {

    //私有属性,仅当前类可以使用
    private int iPR = 0;

    //setter方法
    public void setiPR(int iPR){
        //赋值之前可以对入参进行控制
        if(iPR>10) iPR=add(iPR);
        
        this.iPR=iPR;
    };

    //getter方法
    public int getiPR(){
        return iPR;
    }
    
    //私有方法,仅当前类可以使用
    private int add(int i){
        return i+1;
    }
}
权限修饰符共有public,protected,默认,private四种。将在继承之后统一介绍
权限修饰符也可以修饰外部类,只能使用public和默认
public外部类:该外部类若想被包外的其他类中所访问,可以通过import关键字进行导包。
默认外部类:该外部类无法存在于包外的其他类中,即使导包也没用。

2.继承 ->继承的核心思想是分类(is-a),目的时代码复用
当定义的类越来越多后,为了便于管理要对定义的class进行分类。
同时,为了提高代码复用性,将同一类共同的代码抽出来让所有这一类的class都能使用。
共同使用的代码便重新定义一个class,就是父类。
而其余的class要使用extends关键字和这个公共class产生联系,就是继承。

public class Animal {
    //父类-动物
}

class Cat extends Animal{
    //子类-猫
}

class Dog extends Animal{
    //子类-狗
}

1).Java使用的是单继承,即一个类只能有一个父类,Java中所有类都继承自Object类。
2).final关键字可以修饰类,final修饰的类不可以被继承
3).由于Java的封装性,所以即使是继承关系也不能使用父类所有的成员
    四种权限修饰符
    private:私有的,本类使用
    defalut:默认的,可以省略不写。同包类使用。
    protected:受保护的,同包类+不同包子类使用
    public:公共的,项目中所有类

package com.springlight;

public class Animal {
    //private只能本类内使用
    private void m1(){

    };

    //默认
    void m2(){

    };;

    //受保护的
    protected void m3(){

    };;
    //公共的
    public void m4(){

    };;
}

class Cat extends Animal{

}

class Dog extends Animal{

}

class Bus{
    //同包类
    public void test(){
        Animal animal = new Animal();
        //private修饰的方法不可以使用
        //animal.m1();
        animal.m2();
        animal.m3();
        animal.m4();
    }
}

package com.springliant2;

import com.springlight.*;

public class Pig extends Animal {
    //不同包子类
    public void test(){
        Animal animal1 = new Animal();
        Pig pig = new Pig();
        //private修饰的方法不可以使用
        animal1.m1();
        pig.m1();
        //不同包时,默认修饰符修饰的的方法都不可用
        animal1.m2();
        pig.m2();

        //不同包时,protected修饰的方法,声明的父类对象不可用
        animal1.m3();
        //不同包时,protected修饰的方法,声明的子类对象可用
        pig.m3();

        //不同包时,public都可用
        animal1.m4();
        pig.m4();
    }
}

class Car {
    //不同包非子类
    public void test(){
        Animal animal1 = new Animal();
        Pig pig = new Pig();
        //private修饰的方法不可以使用
        animal1.m1();
        pig.m1();
        //不同包时,默认修饰符修饰的的方法都不可用
        animal1.m2();
        pig.m2();

        //不同包时,protected修饰的方法,声明的父类对象不可用
        animal1.m3();
        //不同包时,protected修饰的方法,声明的子类对象也不可用
        pig.m3();

        //不同包时,public都可用
        animal1.m4();
        pig.m4();
    }
}

4).继承具有传递性,子类本身也可以是其他类的父类。
5).方法重写:当子类继承父类的方法时,子类不想用父类的实现。可以对该方法重新定义
public class Animal {
    
    void m1(){
        System.out.println("父类方法m1");
    };
}

class Cat extends Animal{
    //通过Override注解表示这是个重写方法
    @Override
    void m1() {
        System.out.println("子类方法m1");
    }
}
6).私有方法不能被重写,final修饰的方法不能被重写

public class Animal {

    void m1(){
        System.out.println("父类方法m1");
    };
    
    final void m2(){
        System.out.println("父类方法m2");
    };
}

class Cat extends Animal{
    //这里@Override注解会报错。去掉注解不会报错,但相当于重写定义了新的方法
    @Override
    void m1() {
        System.out.println("子类方法m1");
    }
    
    //这里@Override注解会报错
    @Override
    void m2(){
        System.out.println("子类方法m2");
    };
    
}

7.重写方法的访问权限不能下降,权限访问大小排序为:private<默认<protected<public

public class Animal {
    void m2(){
        System.out.println("父类方法m2");
    };
}

class Cat extends Animal{
    
    //会报错
    @Override
    private void m2(){

    }
}

8).super关键字 -> 提示编译器引用父类的成员

public class Animal {
    
    void m1(){
        System.out.println("父类方法m1");
    };
}

class Cat extends Animal{
    //通过Override注解表示这是个重写方法
    @Override
    void m1() {
        System.out.println("父类方法m1");
    }
    
    void m2(){
        //调用自己的m1方法,也可以用this关键字
        m1();
        //通过父类对象调用父类的m1方法
        super.m1();
    }
}

9).有继承的情况下,创建对象时有以下几点
    内存一次性分配
    只生成一个对象,子类对象包着父类对象,先生成父类对象,再生成子类对象
    有多少父类就调用几次构造函数
    this指代当前对象,super并不指代父类对象。仅提示编译器指向父类的成员
    

10).子类对象创建时会首先创建父类对象并调用父类无参构造器,确保子类对象可以使用父类对象的成员

public class Animal {
    
    {
        System.out.println("父类构造代码块");
    }

    public Animal(){
        System.out.println("父类无参构造方法");
    }
    public Animal(int i){
        System.out.println("父类有参构造方法");
    } 
}

class Cat extends Animal{

    {
        System.out.println("子类构造代码块");
    }

    public Cat(){
        System.out.println("子类无参构造方法");
    }
    
    public Cat(int i){
        System.out.println("子类有参构造方法");
    }
}

public class Main {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        System.out.println("=======================");
        Cat cat2 = new Cat(1);
    }
}

上述Main方法执行结果为:
父类构造代码块
父类无参构造方法
子类构造代码块
子类无参构造方法
=======================
父类构造代码块
父类无参构造方法
子类构造代码块
子类有参构造方法

11).当父类没有无参构造方法时,子类会报错。必须在子类构造方法里手动调用父类构造方法,手动指定后将不在调用父类无参的构造方法
public class Animal {

    {
        System.out.println("父类构造代码块");
    }

    public Animal(int i){
        System.out.println("父类有参构造方法");
    } 
}

class Cat extends Animal{

    {
        System.out.println("子类构造代码块");
    }


    public Cat(){
        //会报错,必须使用super关键字手动调用父类构造方法,而且必须放在第一行
        super(1);
        System.out.println("子类无参构造方法");
    }
    
    public Cat(int i){
        //会报错,必须使用super关键字手动调用父类构造方法,而且必须放在第一行
        super(1);
        System.out.println("子类有参构造方法");
    }
}

public class Main {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        System.out.println("=======================");
        Cat cat2 = new Cat(1);
    }
}

执行结果:
父类构造代码块
父类有参构造方法
子类构造代码块
子类无参构造方法
=======================
父类构造代码块
父类有参构造方法
子类构造代码块
子类有参构造方法


12).创建子类对象的调用过程 ->加载父类,加载子类,创建父类对象,创建子类对象
public class Animal {

    static{
        System.out.println("父类静态代码块");
    }

    {
        System.out.println("父类构造代码块");
    }

    public Animal(){
        System.out.println("父类无参构造方法");
    }
}

class Cat extends Animal{

    static{
        System.out.println("子类静态代码块");
    }

    {
        System.out.println("子类构造代码块");
    }

    public Cat(){
        System.out.println("子类无参构造方法");
    }

    public Cat(int i){
        System.out.println("子类有参构造方法");
    }
}

public class Main {
    public static void main(String[] args) {
        Cat cat1 = new Cat();
        System.out.println("=======================");
        Cat cat2 = new Cat(1);
    }
}

执行结果:
父类静态代码块
子类静态代码块
父类构造代码块
父类无参构造方法
子类构造代码块
子类无参构造方法
=======================
父类构造代码块
父类无参构造方法
子类构造代码块
子类有参构造方法

13).虽然父类构造方法定义在子类构造方法第一行,但实际执行过程中,父类构造方法要先于于子类构造方法执行,甚至先于子类的构造代码块
public class Animal {
    //父类成员变量
    int i ;
    static{
        System.out.println("父类静态代码块");
    }

    {
        System.out.println("父类构造代码块");
        //通过构造代码块给父类对象成员变量赋值
        this.i=0;
        
    }

    public Animal(int i){
        System.out.println("父类有参构造方法");
        //输出此时的成员变量i
        System.out.println(this.i);
        //父类构造方法里再次赋值
        this.i = 1;
        
    }
}

class Cat extends Animal{

    static{
        System.out.println("子类静态代码块");
    }

    {    
        System.out.println("子类构造代码块");
        System.out.println(super.i);
        //子类构造代码块给父类对象的成员属性赋值
        super.i = 2;
        
    }

    public Cat(){
        super(1);
        System.out.println("子类无参构造方法");
        System.out.println(super.i);
    }

    public Cat(int i){
        super(1);
        System.out.println("子类有参构造方法");
        System.out.println(super.i);
    }
}

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

        Cat cat1 = new Cat();
        System.out.println("=======================");
        Cat cat2 = new Cat(1);
    }
}

执行结果
父类静态代码块 --加载父类class,执行父类静态代码块
子类静态代码块 --加载子类class,执行子类静态代码块
父类构造代码块 --创建父类对象,执行父类构造代码块,并给父类对象成员变量i赋值为0
父类有参构造方法 --执行父类有参构造方法
0 --输出父类成员变量i=0,将i赋值为1
子类构造代码块 --执行子类构造代码块
1 --输出此时的父类对象的成员变量i =1,并将i赋值为2
子类无参构造方法 --执行子类构造方法
2 --输出此时的父类对象的成员变量i = 2
=======================
父类构造代码块 --父类子类不必加载,此时创建父类对象,执行父类构造代码块,并给父类对象成员变量i赋值为0
父类有参构造方法 --执行父类有参构造方法
0 --输出父类成员变量i=0,将i赋值为1
子类构造代码块 --执行子类构造代码块
1 --输出此时的父类对象的成员变量i =1,并将i赋值为2
子类有参构造方法 --执行子类构造方法
2 --输出此时的父类对象的成员变量i = 2

3.多态 ->多态的核心思想是方法重写,目的是动态完成同一类对象的不同实现
public class Animal {
    public void m1(){
        System.out.println("Animal的m1");
    };
}

class Cat extends Animal{

    @Override
    public void m1(){
        System.out.println("Cat的m1");
    }
}

class Dog extends Animal{

    @Override
    public void m1(){
        System.out.println("Dog的m1");
    }
}

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

        Animal animal1 = new Animal();
        Animal animal2 = new Cat();
        Animal animal3 = new Dog();

        animal1.m1();
        animal2.m1();
        animal3.m1();
    }
}

运行结果为:
Animal的m1
Cat的m1
Dog的m1

1).里氏代换原则:任何基类出现的地方,使用派生类都不应该有问题
2).向上转型: 父类声明 = new 子类对象
   向下转型(需要强转):子类声明 = (子类)new 父类对象

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值