面向对象

183 阅读12分钟

类与对象

  • java中要想创建对象,必须先要有类的存在。
  • 类指的是一组相关属性和行为的集合,我们将其理解为是一张对象的设计图

类的组成

  • 属性:成员变量,跟之前定义变量的格式一样,只不过位置需要放在类中方法外。
  • 行为:成员方法,跟之前定义方法的格式一样,只不过需要去掉static关键字。

代码示例

public class Person {
    private int age;
    private String name;

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

成员变量和局部变量

区别成员变量局部变量
类中位置不同方法外方法内
初始化值不同有默认的初始化值没有,使用之前需要完成赋值
内存位置不同堆内存栈内存
生命周期不同随着对象的创建而存在,随着对象的消失而消失随着方法的调用而存在,随着方法的运行结束而消失
作用域在自己所归属的大括号里面在自己所归属的大括号里面

this关键字

this代表当前类对象的引用(地址)

构造方法

构造器

  • 初始化一个新建的对象
  • 构建、创造对象的时候所调用的方法

格式

  • 方法名与类名相同,大小写也一样
  • 没有返回值类型,连void都没有
  • 没有具体的返回值类型(不能由retrun带回结果数据)

执行时机

  • 创建对象的时候调用,每创建一次对象,就会执行一次构造方法
  • 不能手动调用构造方法

构造方法的作用

  • 本质作用:创建对象
  • 结合构造方法执行时机:给对象中的属性(成员变量)进行初始化

构造方法的注意事项

  • 构造方法的创建
    • 如果没有定义构造方法,系统将会给出一个默认的无参构造方法
    • 如果定义了构造方法,系统将不再提供默认的构造方法
  • 构造方法重载
    • 构造方法也是方法,也可以重载
  • 推荐使用方式
    • 无参构造方法,和带参构造方法,都手动自己给出

代码示例

public class Person {
    private int age;
    private String name;

    public Person() {

    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}

class Demo{
    public static void main(String[] args) {
        Person bob = new Person(20, "bob");
    }
}

static关键字

static关键字介绍

static是静态的意思,可以修饰成员变量,也可以修饰成员方法。

static修饰成员的特点

  • 被其修饰的成员,被该类的所有对象共享
  • 多了一种调用方式,可以通过类名调用
  • 随着类的加载而加载,优先于对象存在

static用途

  • static修饰成员变量:共享数据
  • static修饰成员方法:常用于工具类

static注意事项

  • static方法中,只能访问静态成员(直接访问)
  • static中不允许出现this关键字

继承

继承介绍

继承:让类与类之间产生关系(父子关系),子类可以直接使用父类中的非私有的成员

什么时候使用继承?

当类与类之间,存在相同(共性)的内容,并且产生了 is a 的关系,就可以考虑使用继承,来优化代码。

继承中成员的访问特点

  • 成员变量:子父类中,如果出现了重名的成员变量,使用的时候根据就近原则,优先使用子类的。要想使用父类的通过super关键字进行解决
  • 成员方法:父类中私有的方法不能被重写,子类重写父类的方法时,访问权限必须大于等于父类
  • 构造方法:在所有的构造方法中,都默认隐藏了一句话super();通过这句代码,来访问父类的空参构造方法

权限修饰符

权限修饰符不同包的无关类不同包的子类同一个包中同一个类中
publicYYYY
protectedNYYY
默认NNYY
privateNNNY

this和super

  • this:代表本类对象的引用
  • super:代表父类存储空间的标识

注意:this()和super()都在争夺构造方法的第一行的位置,所以二者不能共存。

java继承特点

java只支持单继承,不支持多继承,但支持多层继承。

final关键字

final关键字标识最终的意思,可以修饰类、方法、变量

final修饰的特点:

  • 修饰方法:表明该方法是最终方法,不能被重写
  • 修饰类:表明该类是最终类,不能被继承
  • 修饰变量:表明该变量是常量,不能再次赋值

final修饰变量的细节补充:

  • 变量是基本类型:final修饰指的是基本类型的数据值不能发生改变
  • 变量是引用类型:final修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以发生改变的
  • 成员变量如果被final修饰,需要在构造方法结束之前完成赋值

  • 包本质来说就是文件夹,用来管理文件的
  • 建包的语法格式:package 公司域名倒写.技术名称。包名建议全部英文小写,且具备意义
  • 建包语句必须在第一行,一般idea工具会帮助创建

导包

  • 相同包下的类可以直接访问,不同包下的类必须导包,才可以使用!导包格式:import 包名.类名;
  • 假如一个类中需要用到不同类,而这两个类的名称是一样的,那么默认只能导入一个类,另一个类要带包名访问。

抽象类

抽象类是一种特殊的父类,内部可以编写抽象方法

抽象方法

  • 抽象方法:将共性的行为(方法)抽取到父类之后,发现该方法的实现逻辑无法在父类中给出具体明确,该方法就可以定义为抽象方法
  • 抽象类:如果一个类中存在抽象方法,那么该类就必须声明为抽象类。

抽象类和抽象方法定义格式

public abstract class 类名 {}

public abstract 返回值类型 方法名(参数列表);

注意事项

  • 抽象类不能实例化
  • 抽象类存在构造方法
  • 抽象类中可以存在普通方法
  • 抽象类的子类
    • 要么重写抽象类中的所有抽象方法
    • 要么子类是抽象类

abstract关键字的冲突

  • final:被abstract修饰的方法,强制要求子类重写,被final修饰的方法子类不能重写
  • private:被abstract修饰的方法,强制要求子类重写,被private修饰的方法子类不能重写
  • static:被static修饰的方法可以类名调用,类名调用抽象方法没有意义

接口

体现的思想是对规则的声明,java中的接口更多体现的是对行为的抽象

  • 接口用关键字interface来定义:public interface 接口名{}
  • 接口不能实例化
  • 接口和类之间是实现关系,通过implements关键字来表示
    • public class 类名 implements 接口名{}
  • 接口的子类(实现类)
    • 要么重写接口中的所有抽象方法
    • 要么是抽象类

接口中的成员特点

  • 成员变量:只能是常量,默认修饰符是public static final
  • 构造方法:没有
  • 成员方法:只能是抽象方法,默认修饰符public abstract,关于接口中的方法,jdk8和jdk9中有一些新特性

类和接口之间的各种关系

  • 类和类的关系:继承关系,只能单继承,但是可以多层继承
  • 类和接口的关系:实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
  • 接口和接口的关系:继承关系,可以单继承,也可以多继承

抽象类和接口的区别

  • 成员变量:
    • 抽象类:可以定义变量,也可以定义常量
    • 接口:只能定义常量
  • 成员方法:
    • 抽象类:可以定义抽象方法,也可以是具体方法
    • 接口:只能定义抽象方法
  • 构造方法:
    • 抽象类:有
    • 接口:没有

抽象类和接口的对比

  • 抽象类:是事物做抽象(描述事物)
  • 接口:对行为抽象(制定规则)

多态

同一个行为具有多个不同表现形式或形态的能力

多态前提

  • 有继承/实现关系
  • 有方法重写
  • 有父类引用指向子类对象

多态的成员访问特点

  • 成员变量:编译看左边(父类),执行看左边(父类)
  • 成员方法:编译看左边(父类),执行看右边(子类)

多态的好处和弊端

  • 多态的好处:提高了程序的扩展性
    • 对象多态:将方法的形参定义为父类类型,这个方法可以接收该父类的任意子类对象。
    • 行为多态:同一个行为,具有多个不同表现形式或形态的能力
  • 多态的弊端:不能使用子类的特有成员

多态中的转型

  • 向上转型:从子到父(父类引用指向子类对象)
  • 向下转型:从父到子(将父类引用所指向的对象,转交给子类类型)

多态中的转型问题

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException

  • 关键字:instanceof
  • 使用格式:
    • 对象名 instanceof 类型
    • 判断一个对象是否是一个类的实例
    • 通俗的理解:判断关键字左边的对象,是否是右边的类型,返回boolean类型结果

接口新特性

  • jdk8的新特性:接口中可以定义有方法体的方法。(默认、静态)
  • jdk9的新特性:接口中可以定义私有的方法。

jdk8接口特性

允许在接口中定义非抽象方法,但是需要使用关键字default修饰,这些方法就是默认方法,作用:解决接口升级的问题

接口中默认方法的定义格式:public default 返回值类型 方法名(参数列表){}

注意事项:

  1. 默认方法不是抽象方法,所以不强制被重写(但是可以被重写,重写的时候去掉default关键字)
  2. public 可以省略,defalut不能省略
  3. 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写。

允许在接口中定义static静态方法

接口中静态方法的定义格式:public static void show(){}

注意事项:

  1. 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
  2. public可以省略,static不能省略

jdk9接口新特性

接口中允许定义private私有方法

接口中静态方法的定义格式:

  • 格式1:private 返回值类型 方法名(参数列表){}
  • 格式2:private static 返回值类型 方法名(参数列表){}

代码块

在java类下,使用{}括起来的代码被称为代码块

分类:

  • 局部代码块
    • 位置:方法中定义
    • 作用:限定变量的生命周期,及早释放,提高内存的利用率
  • 构造代码块
    • 位置:类中方法外
    • 特点:每次构造方法执行的时候,都会执行该代码中的代码,并且在构造方法执行前执行
    • 作用:将多个构造器方法中相同的代码,抽取到构造代码块中,提高代码的复用性
  • 静态代码块
    • 位置:类中方法外定义
    • 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
    • 作用:在类加载的时候做一些数据初始化的操作。
  • 同步代码块

内部类

内部类就是定义在一个类里面的类,封装性更好

public class Outter {
    class inner {
    }
}

创建对象的格式:外部类类名.内部类类名 变量名=new 外部类对象().new 内部类对象();

Outter.inner inner = new Outter().new inner();

内部类成员访问

  • 内部类,访问外部类成员:直接访问,包括私有的。
  • 外部类中,访问内部类成员:需要创建对象访问
  • 在成员内部类中访问所在外部类对象,格式:外部类名.this

分类

成员内部类

静态内部类:有static修饰的成员内部类

public class Outer {
    static class Inner {
    }
}

class Demo {
    public static void main(String[] args) {
        //静态内部类创建格式
        //外部类名.内部类名 对象名=new 外部类类名.内部类对象();
        Outer.Inner inner = new Outer.Inner();
    }
}

局部内部类:放在方法,代码块,构造器等执行体中。鸡肋语法,了解即可

匿名内部类:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部),前提:需要存在一个接口或类,匿名内部类可以作为方法的实际参数进行传输

//匿名内部类可以使代码更加简洁,定义一个类的同时对其进行实例化
new 类名/接口(){}

Lambda表达式

  • lambda表达式是jdk8开始后的一种新语法形式。
  • 作用:简化匿名内部类的代码写法

格式

()->{}

(匿名内部类被重写方法的形参列表)->{ 被重写方法的方法体代码。 }

注意:lambda表达式只能简化函数式接口的匿名内部类的写法形式

什么是函数式接口?

  • 首先必须是接口,其次接口中有且仅有一个抽象方法的形式
  • 通常我们会在接口上加上一个@FunctionlInterface注解,标记该接口必须是满足函数式接口。

lambda表达式的省略写法

  • 参数类型可以省略不写。
  • 如果只有一个参数,参数类型可以省略,同时()也可以省略。
  • 如果lambda表达式的方法体代码只有一行代码,可以省略大括号不写,同时要省略分号,此时,如果这行代码是return语句,必须省略return不写,同时也必须省略“;”不写

lambda表达式和匿名内部类的区别

  • 使用限制不同
    • 匿名内部类:可以操作类,接口。
    • lambda表达式:只能操作函数式接口
  • 实现原理不同
    • 匿名内部类:编译之后,会产生一个单独的.class字节码文件
    • lambda表达式:编译之后,没有一个单独的.class字节码文件