【Java】06 面向对象基本特征

面向对象的三大基本特征:封装、继承、多态。

一、封装

1.1 概述

1.1.1 什么是封装

   封装(Encapsulation)是面向对象的三大特征之一,它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类所提供的方法来实现对内部信息的操作和访问。采用封装的思想保证了类内部数据结构的完整性,使用该类的用户不能轻易地直接操作此数据结构,只能操作类允许公开的数据。这样就避免了外部操作对内部数据的影响,提高了程序的可维护性。

1.1.2 访问控制符
同一个类中同一个包中不同包的子类不同包的无关类
public
protected
default
private

   public(公共访问权限):这是一个最宽松的访问控制级别,如果一个成员(包括成员变量、方法和构造器等)或者一个外部类使用 public 访问控制符修饰,那么这个成员或外部类就可以被所有类访问,不管访问类和被访问类是否处于同一个包中,是否具有父子继承关系。
   protected(子类访问权限):如果一个成员(包括成员变量、方法和构造器等)使用 protected 访问控制符修饰,那么这个成员既可以被同一个包中的其他类访问,也可以被不同包中的子类访问。在通常情况下,如果使用 protected 来修饰一个方法,通常是希望其子类来重写这个方法。
   default(包访问权限):如果类里的一个成员(包括成员变量、方法和构造器等)或者一个外部类不使用任何访问控制符修饰,就称它是包访问权限的,default 访问控制的成员或外部类可以被相同包下的其他类访问。
   private(当前类访问权限):如果类里的一个成员(包括成员变量、方法和构造器等)使用private访问控制符来修饰,则这个成员只能在当前类的内部被访问。很显然,这个访问控制符用于修饰成员变量最合适,使用它来修饰成员变量就可以把成员变量隐藏在该类的内部。

1.1.3 this 关键字
public class Test {

	int a = 3;

    public static void main(String[] args) {
        test(5);
    }
    
    public void test(int a) {
        System.out.println(a); // 5
    }
}

   运行上述代码可以看到输出的是 5 ,而不是 3。这就是 Java 的就近原则,如果想要输出 5 则需要借助 this 关键字,this 代表所在类当前对象的引用,即谁调用就代表谁。

1.1.4 final 关键字

   final 修饰类,被修饰的类不能被继承、修饰方法,被修饰的方法不能被重写、修饰变量,被修饰的变量不能重新赋值。

// 修饰类
final class 类名{ ··· }
// 修饰方法
final 返回值类型 方法名( 参数列表 ) { ··· }
// 修饰变量
final 数据类型 变量名;

1.2 类的封装

1.2.1 封装步骤

(1)私有化
   使用 private 关键字修饰成员变量,使其私有化。
(2)暴露方法
   提供 setXXX()/getXXX()方法来设置和获取成员变量。
(3)this
   在成员方法中局部变量和成员变量重名是就需要使用 this 了。

1.2.2 示例
public class Add {
    // 私有成员变量
    private int a;
    private int b;

    // 提供公共访问方法
    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }

    //成员方法
    public int add() {
        int sum = a + b;
        return sum;
    }
}

1.3 构造方法

1.3.1 什么是构造方法

   在类中除了成员方法之外,还存在一种特殊类型的方法,那就是构造方法。构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会自动调用构造方法。

1.3.2 语法
public 构造方法名( 参数列表 ) {
    方法体;
}
1.3.3 注意

  构造方法名与类名必须一致。
  有参数的构造方法称为有参构造,没有参数的构造方法称为空参构造。
  构造方法可以重载,但无论如何,Java类至少包含一个构造器。
  若没有写任何构造方法,JVM 会自动帮你写一个空参构造。

1.3.4 示例
public class Test {
    // 成员变量
    private int a;
    private int b;

    // 空参构造
    public Test() {
    }
	
	// 有参构造
    public Test(int a, int b) {
        this.a = a;
        this.b = b;
    }

    //set/get方法
    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    public int getB() {
        return b;
    }

    public void setB(int b) {
        this.b = b;
    }
}

二、继承

2.1 概述

2.1.1 什么是继承

   继承的基本思想是基于某个父类的扩展,并制定出一个新的子类,子类可以继承父类原有的属性和方法,也可以增加原来父类所不具备的属性和方法,或者直接重写父类中的某些方法。

2.1.2 extends 关键字

   在 Java 中,让一个类继承另一个类需要使用 extends 关键字,子类在继承父类的同时,也继承了父类中的属性和方法。

2.1.3 super 关键字

   子类可以重写父类中的方法,但是再重写之后想要调用父类中的方法需要借助 super 关键字,super 关键字代表父类对象。

2.2 类的继承

2.2.1 语法
public class 父类 { ··· }
public class 子类 extends 父类 { ··· }
2.2.2 注意

(1)成员变量:
   不重名没有影响,使用谁就是谁。
   重名则 new 谁就是谁的 ( 开发中一般不会重名 ),此时如果要使用父类的非私有成员变量与需要使用 super.父类成员变量名。
(2)成员方法:
   不重名没有影响,使用那个方法就是那个方法。
   重名则为子类重写(覆盖)父类方法,声明不变,重新实现。
(3)构造方法:
   构造方法名与类名一致,所以不能被继承。
   构造方法是用来初始化成员变量的,所以子类初始化的过程中,父类必须先于子类初始化。即调用构造方法时,一定先调用父类的构造方法。
   子类的空参构造中会默认写有 super(),表示调用父类的构造方法,父类的成员变量初始化之后才可以给子类使用。
(4)其他注意事项:
   子类覆盖父类方法是,必须保证子类方法权限大于父类。
   子类覆盖父类方法要保证,权限、返回值、方法名、参数列表一模一样。
   类的继承只支持单继承,不支持多继承
   所有类的父类都是 Object

2.2.3 示例
// 父类,手机类
public class Phone {
    // 成员变量
    private String brand;
    private String price;

    // 构造方法
    public Phone() {
    }

    public Phone(String brand, String price) {
        this.brand = brand;
        this.price = price;
    }

    // 成员方法
    public void call() {
        System.out.print("打电话!");
    }

    public void send() {
        System.out.println("发短信!");
    }

    public void show() {
        System.out.println(brand + "牌手机,售价" + price);
    }
}

// 子类,小米手机
public class MiPhone extends Phone{
    // 构造方法
    public MiPhone() {
        // 默认有 super();
    }

    public MiPhone(String brand, String price) {
        super("mi 10 pro","3999");
    }

    //重写父类方法
    @Override
    public void call() {
        super.call();   //调用父类原有 call() 方法

		// 子类新增功能
        System.out.print("显示姓名! ");
        System.out.print("显示号码! ");
    }

    //子类特有方法
    public void inter() {
        System.out.println("上网!");
    }
}

//测试类
public class test {
    public static void main(String[] args) {
        //new 对象
        MiPhone mp = new MiPhone();

        //调用父类方法
        mp.send();		// 发短信!
        
        //调用子类重写方法
        mp.call();			// 打电话!显示姓名! 显示号码!

        //调用子类特有方法
       	mp.inter();			// 上网!
    }
}

三、多态

3.1 抽象

3.1.1 概述

(1)抽象方法:使用 abstract 修饰的没有方法体的方法称为抽象方法。
(2)抽象类:包含抽象方法的类称为抽象类。

3.1.2 语法
修饰符 class abstract 类名 {
	修饰符 abstract 返回值类型 方法名(); 
}
3.1.3 注意

   抽象类不能创建对象。
   抽象类中可以有构造方法,是提供给子类创建对象时初始化父类成员变量使用。
   子类需重写父类所有的抽象方法,除非子类也是抽象类。
   抽象方法一定要在抽象类中,抽象类不一定要有抽象方法。
   最终必须有子类是实现父类所有的抽象方法。

3.1.4 示例
//父类,抽象类
public abstract class Fu {
    public abstract void num();
}

//子类,实现父类
public class Zi extends Fu{
    public void num() {
        System.out.println("子类");
    }
}

3.2 接口

   接口是Java中一种引用类型,是方法的集合。接口中主要封装了方法,包含抽象方法(JDK 1.7 之前),默认方法、静态方法(JDK 8),私有方法(JDK 9)。

3.2.1 语法
public interface 接口名{
        //抽象方法(JDK 1.7 之前)
        //默认方法(JDK 8)
        //静态方法(JDK 8)
        //私有方法(JDK 9)
}
3.2.2 接口的使用

(1)抽象方法(☆☆☆☆☆)

//与抽象类相似
public interface Inter{
    public abstract void method();
}

(2)默认方法

//主要用于升级接口,防止以前的实现类报错,新创建的实现类可以覆盖默认方法。
//接口中有多个默认方法是,实现类都可以继承使用。
public interface Inter{
    public default void method(){
        System.out.println("run···");
    }
}

(3)静态方法

//直接使用接口已经完成的现成功能。
public interface Inter{
    public static void method(){
        System.out.println("run···");
    }
}

(4)私有方法

//用于抽取接口中相同的代码块
//1.私有方法:只有默认方法可以调用
public default void methodA(){
    method();
}
public default void methodB(){
    method();
}
private void method() {
    System.out.println("runA···");
    System.out.println("runB···");
}

//2.私有静态方法:默认方法和静态方法都可以调用
public default void methodA(){
    method();
}
public static void methodB(){
    method();
}
private static void method() {
    System.out.println("runA···");
    System.out.println("runB···");
}

注意:
  接口不能直接 new
  调用接口原本的默认方法:接口名.super.默认方法名();
  静态方法属于接口,只能通过:接口名.静态方法名() 调用。

3.2.3 接口的多实现
// 继承并实现
public class 类名 extends 抽象类 implement 接口名{
    //方法体
}  
// 多实现
public class 类名 [ extends Object ] implement 接口名1, 接口名2,··· ,接口名n {
    //方法体
}
// 多继承
public interface 类名 extends 接口名1, 接口名2,··· ,接口名n {
    //方法体
}

注意:
  如果抽象方法有重名,则只需要重写一次。
  如果默认方法有重名,则必须重写。
  那个接口在前则那个接口优先级高。

3.3 多态

   Java 引用变量有两个类型:一个是编译时类型,一个是运行时类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就可能出现所谓的多态。

3.3.1 语法
// 父类引用指向子类对象
父类 变量名 = new 子类();

// 接口引用指向实现类对象
接口 变量名 = new 实现类();
3.3.2 注意

   多态调用成员变量时:编译看左,运行看左。即:父类没有则不能使用
   多态调用成员方法时:编译看左,运行看右。即:父类没有则不能通过编译

3.3.3 类型转换

向上转型(默认)

父类 类名 = new 子类();

  为什么要想上转型:父类类型作为方法形式参数,传递子类对象,更能体现多态的扩展性与便利性
向下转型(强制)

子类 类名1 = ( 子类 )  类名2;

  为什么要向下转型:使用多态方式无法调用子类特有方法。
  向下转型需要注意只有以前是这个类才能转。
instanceof 关键字
  用来判断向下转型时是否属于该类。例如: 动物A instanceof 猫;

3.3.4 示例
//父类
public abstract class Phone {
    public abstract void price();
}

//子类,联想
public class LenovoPhone extends Phone{
   public void newPrice() {
       System.out.println("3999");
   }
}

//子类,华为
public class HonorPhone extends Phone{
   public void newPrice() {
       System.out.println("6999");
   }
}

//测试类
public class Test{
    public static void main(String[] arg) {
        //父类引用指向子类对象
        Phone phone = new LenovoPhone();

        method(phone);

    }

    //判断属于那个子类
    public void method(phone phone) {
        if(phone instanceof LenovoPhone) {
            //向下强转
            LenovoPhone lp = (LenovoPhone)phone;
            //调用联想手机类独有方法
            lp.newPrice();
            System.out.println("这是联想手机");
        }
        if(phone instanceof HonorPhone) {
            //向下强转
            HonorPhone hp = (HonorPhone)phone;
            //调用华为手机类独有方法
            hp.newPrice();
            System.out.println("这是华为手机");
        }
    }
}

四、内部类

4.1 成员内部类

4.1.1 语法
//外部类
class 类名 {
    //内部类
    class 类名 {
        ···
    }
}
4.1.2 注意

   成员内部类定义在类中方法外
   内部类可以直接访问外部类的成员,包括私有成员
   外部类要想访问内部类的成员必须先创建内部类对象

4.2 局部内部类

4.2.1 语法
// 外部类
class 类名 {
	// 方法
    修饰符 返回值类型 方法名( 参数列表 ) {
        class 类名 {    //局部内部类
            ···
        }
    }
}
4.2.2 注意

   局部内部类定义在方法中
   局部内部内在堆中,局部变量在栈中,方法出栈后,局部变量消失,局部内部类等待 JVM 回收

4.3 匿名内部类 ☆☆☆☆☆

4.3.1 语法
父类或接口名 对象名 = new 父类或接口 {
    //方法重写
    @Override
}
4.3.2 注意

   【等号左边】 是多态,父类引用指向子类对象。
   【等号右边】 定义并创建父类或接口的类对象。
   匿名内部类是省略了【实现类/子类】名称,匿名对现象是省略了【对象名】。

4.3.3 示例
//接口
public interface Inter {
    //抽象方法
    public abstract void method();
}

//测试类
public class InterAnonymous {
    public static void main(String[] ards) {
        //匿名内部类
        new Inter {
            public void method() {
                System.out.println("使用了匿名内部类和匿名对象");
            }
        }.method();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值