【Java 系列笔记】02 Java 面向对象

Content

  • Java 面向对象
    • 封装
      • 类的定义
      • 类的访问权限
      • getter 和 setter
      • 导包
      • 实例化对象
      • 静态代码块
    • 继承
      • 继承
      • 访问父类`super`
      • 重写
        • 注解(Annotation)
            • 作用在代码的注解:
            • 作用在其他注解的注解(或者说 元注解):
            • 从 Java 7 开始,额外添加了 3 个注解:
      • 抽象类
      • 接口
    • 多态
      • 多态
      • `instanceof`判断实例
    • 内部类
      • 成员内部类
      • 局部内部类
      • 匿名内部类

Java 面向对象

封装

类的定义

class Type{
    public String _var; // 成员属性
    public Type(...){ // 构造方法
        // ...
    }
    public void method)(...){ // 成员方法
        // ...
    }
}

类的访问权限

在 Java 中,public、private、protected 这些访问权限必须直接修饰方法,而不是 C++ 分类式地声明。

class Type{
    public int field;
    public void method(){
        //...
	}
}

Java 中有四种权限修饰方式:

修饰符 访问范围
public 均可访问
protected 包外非子类无法访问
(缺省) 包外均无法访问
private 仅本类访问

getter 和 setter

用于对数据进行访问保护。

一般情况都这样写:

public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}

bool 比较特别:

public boolean isMale() {
return te;
}

public void setMale(boolean male) {
this.amle = male;
}

导包

导入类:

import top.gaolihai.Type;

类的作用域在整个包内,故若与某类在同一个包,可以不导入,直接使用。

实例化对象

Type obj = new Type();

静态代码块

class Type {
    static {
 		// ...       
    }
}

首次使用该类时(不论以何种方法),会直接调用静态代码块。

相当于对静态成员的构造函数。

继承

继承

关键字:extends

class Son extends Father {
    // ...
}

访问父类super

关键字:super

子类构造隐式调父类的默认构造。super()

当不存在默认构造时,需要手动调用,且必须为第一个语句:

class Son extends Father {
    public Son (int param) {
        super(param); // 手动调 super
        // ...
    }
    public void method() {
    	super.field;
        super.method();
        // ...
    }
}

可以访问到所有父辈类的 constructor、method 及 field。

另外地,也可以通过this调用本类构造:

用于为构造函数提供默认值(Java 中没有默认参数)。

class Type {
    public Type() {
        this(10);
    }
    public Type (int param) {
        // ...
    }
}

重写

重写父类方法,实现动态多态。也叫(覆盖,覆写)

!!! 注意:

  • 为防止寻址超出范围,子类返回值不允许是父类返回值的父辈类

    C++ 允许这样做,但不保证安全,所以 Java 禁止了。

  • 为防止发生多态时无法访问子类重写变为 pirvate 的方法,Java 禁止子类用 private 方法重写父类的 public 方法

    C++ 同样允许这样做,但当试图访问不可访问的方法时,编译出错。

    Java 允许访问范围较大的重写访问范围较小的,具体表现为:

    public > protected > (默认) > private

    还要注意的是,父类的 private 方法无法被重写。在子类写同名方法不会出错,但这不是重写,而是一个新方法。

class Father {
    public void method() {
		// ...
    }
}
class Son extends Father {
    public void method() {
		// ...
    }
}

推荐使用注解:

@override用于检测是否发生了正确的重写,是一种安全检测手段。

注解后若未正确重写会出现编译错误。

class Son extends Father {
    @override
    public void method() {
		// ...
    }
}

注解(Annotation)

作用在代码的注解:
  • @Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
  • @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
  • @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解):
  • @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
  • @Documented - 标记这些注解是否包含在用户文档中。
  • @Target - 标记这个注解应该是哪种 Java 成员。
  • @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
从 Java 7 开始,额外添加了 3 个注解:
  • @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
  • @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
  • @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

抽象类

抽象类中可以存在抽象方法:

abstract class Father {
    abstract void method();
}

与 C++ 不同,抽象类必须直接使用abstract修饰。才允许定义抽象方法。

子类重写父类抽象方法:

class Son extends Father {
    void method() {
        // ...
    }
}

接口

接口是多个类的公有规范

关键字:interfaceimplementsdefault

由于接口仅是规范,其中的方法均为抽象方法,且不存在构造方法和静态代码块。

接口可以包含这些内容:静态常量、抽象方法、默认方法(Java 8)、静态方法(Java 8)、私有方法(Java 9)

默认方法用于方便地进行**接口升级**。

静态方法仅允许通过接口直接调用,防止出现命名冲突。

定义一个接口:

其中的方法会被隐式修饰为public abstract,变量会被隐式修饰为public static final

interface _Interface {
    // 静态变量
    public static final int field;
    
    // 抽象方法
    public abstract void method();
    
    // 默认方法
    public default void defaultMethod() {
        // ...
    }
    
    // 静态方法
    public static void staticMethod() {
        // ...
    }
    
    // 私有方法
    private void privateMethod() {
        // ...
    }
    private static void privateStaticMethod() {
        // ...
    }
}

接口的实现:

class specific implements _Interface{
    @Override
    public void method() {
        // ...
    }
    // ...
}

接口允许继承且允许多继承:

interface _Interface extends _Interface1, _Interface2 {
	// ...
}

前面提到,Java 为了防止出现二义性的问题,不允许类的多继承。

而接口都是抽象的,由开发者来实现,那么也就不存在多继承二义性的问题。

(对于默认方法的二义性,多重继承时会被要求必须重写冲突的默认方法)

interface _Interface1 {
    public default void method() {
        // ...
    }
}

interface _Interface2 {
    public default void method() {
        // ...
    }
}

public interface _Interface extends _Interface1, _Interface2 {
    @Override
    default void method() {
        _Interface1.super.method();
    }
}

一个类可以同时继承类和实现接口:

且在发生冲突时默认调用继承来的父类的方法。

在 Java 中,继承较实现接口更优先一些。

public Son extends Father implements _Interface1 {
	// ...
}

多态

多态

多态的抽象表述:接口与实现的分离

具体一些可以称:父类指针(引用)指向子类对象

为了访问安全性,Java 不允许父类对象(实际上的)向下转型。会抛出ClassCastException异常。

instanceof判断实例

关键字:instanceof

返回一个 boolean值,表示前边的对象是否是后边类型的实例。

obj instanceof Type;
if (obj instanceof Son) {
    ((Son) obj).specificMethod();
}

其他的内容与 C++ 基本一致,不赘述。

内部类

成员内部类

在类内部定义类:

成员内部类允许使用各种权限修饰符。

class Outer {
    //...
    
    class Inner { // 成员内部类
        //...
    }
    
    //...
}

注意,内部类不能存在静态声明。

实例化:

Outer.Inner obj = new Outer().new Inner();

内部类可以随意访问外部类的内容:

class Outer {
	int field;
    
    class Inner { // 内部类
        int field;
        void method() {
            Outer.this.field; // 通过外部类名.this 访问
        }
    }
}

局部内部类

即方法内部的类:

局部内部类不允许使用任何修饰符,因为没有意义,仅当前方法的作用域可以完全访问。

class Outer {
    //...
    
    public void method() {
        //...
        
        class Inner { // 局部内部类
            //...
        }
        
        //...
    }
    
    //...
}

注意,局部内部类对当前方法作用域的访问是受限的,它仅可访问finaleffectively final的变量。必须保证内部类访问到的外部变量没有被实际改变过。

effectively final即 “最终有效 final” 。

这是由于,当前方法栈出栈后,栈变量也随即释放。故欲访问当前作用域,必须保证欲访问的变量是一个常量。

匿名内部类

对于一个接口:

interface _Interface {
    void method();
}

我们可以在方法内直接实例化一个匿名内部类:

需要实现接口的所有方法。

_Interface obj = new _Interface() {
    @Override
    public void method() {
        //...
    }
};

或者直接调用方法:

new _Interface() {
    @Override
    public void method() {
        //...
    }
}.method();

你可能感兴趣的:(Java,笔记,多态,抽象类,java,接口,封装)