1 面向对象基础

1.1 类的定义

基本信息

  • 类的基本组成
    • 成员变量(属性):
    • 成员方法(行为):成员方法不含 static 关键字
  • 面向对象三大特征: 封装继承多态 ```java public class Student { String name; int age; public void eat(){
    1. System.out.println("Eat!");
    } public void sleep(){
    1. System.out.println("Sleep");
    }

}

  1. - **局部变量与成员变量的区别**
  2. - 定义的位置不同(局部变量在方法内部,成员变量在方法外部)
  3. - 作用范围不同(局部变量只在方法内部生效,成员变量在整个类上通用)
  4. - 默认值不同(局部变量没有默认值,成员变量若无赋值,会有默认初值,规则与数组默认值相同)
  5. - 内存位置不同(局部变量位于栈内存,成员变量位于堆内存)
  6. - 生命周期不一样(局部变量随着方法进栈而诞生,随着方法出栈而消失;成员变量随着对象创建而诞生,随着对象被垃圾回收而消失)
  7. <a name="QRUEO"></a>
  8. ### private 关键字的作用
  9. - 用于保护成员变量
  10. - 一旦使用了 **private** 关键字,本类当中依然可以随意访问,但是超出本类范围之外则不可直接访问
  11. - 间接访问成员变量,则定义一对 **getter** **setter** 方法
  12. - 对于基本类型中的 **boolean** ,其 **getter** 方法要写成 is`Xxx` 形式
  13. ```java
  14. public class Person {
  15. String name;
  16. private int age;
  17. private boolean male;
  18. public void setMale(boolean b) {
  19. male = b;
  20. }
  21. public boolean isMale() {
  22. return male;
  23. }
  24. public void setAge(int num) {
  25. age = num;
  26. }
  27. public int getAge() {
  28. return age;
  29. }
  30. public void show() {
  31. System.out.println("姓名:" + name);
  32. System.out.println("年龄:" + age);
  33. }
  34. }

this 关键字的作用

  • 当方法的局部变量和成员变量重名的时候,使用 this 将其区分

    static 关键字

  • 使用 static 关键字表明成员属性或成员方法直属于类,不单独属于任一对象

  • 如果没有 static ,必须首先创建对象,通过对象再来使用它
  • 否则,如果有 static , 则可以通过类名直接调用
  • 本类当中定义的static方法在调用时可以省略类名称
  • 注意: 静态方法不能直接访问非静态成员静态方法中不可使用 this (静态的总是优先于非静态的)
  • 静态代码块(典型用途:用来一次性对静态变量赋值)

    1. public class Person{
    2. static{
    3. System.out.println("第一次使用此类时,静态代码块执行唯一的一次");
    4. }
    5. }

    1.2 对象的创建及使用

    基本概念

  • 导包 import 包名称.类名称

  • 创建对象 类名称 对象名 = new 类名称()
  • 使用对象:使用运算符 .

    对于和当前类属于同一个包的情况,可以省略导包语句不写 只有 java.lang 包下的内容不需要 import

  1. public class Student {
  2. String name;
  3. int age;
  4. public void eat() {
  5. System.out.println("Eat!");
  6. }
  7. public void sleep() {
  8. System.out.println("Sleep!");
  9. }
  10. public static void main(String[] args) {
  11. Student stu = new Student();
  12. stu.name = "Musou";
  13. stu.age = 24;
  14. System.out.println(stu.name + " " + stu.age);
  15. stu.eat();
  16. stu.sleep();
  17. }
  18. }

构造方法

  • 专用于创建对象的方法
  • 构造方法的名称必须和所在类名称完全一样
  • 构造方法不需要写返回值类型, void 也不用写,构造方法同时也不可产生返回值
  • 如果没有自己编写构造方法,编译器默认给出一个无参构造方法
  • 若编写了自己的构造方法,编译器则不再给出默认构造方法

标准类(Java Bean)

一个标准的类通常由以下四个部分组成

  • 所有的成员变量使用 private 进行修饰
  • 为每一个成员变量编写一对getter/setter方法
  • 编写一个无参数的构造方法
  • 编写一个有参数的构造方法

    1.3 API及其使用

    1.4 匿名对象

  • 只有对象,没有赋值 new 类名称()

  • 匿名对象只能使用唯一一次
  • 匿名对象可以作为返回值与参数

    1. new Person().name = "Musou";


    2 继承

    2.1 继承的基本概念

    继承是多态的前提,没有继承,就没有多态

  • 继承的格式 public class childClass extends parentClass{}

  • Java继承的三个特点

    • 单继承:一个类的直接父类只能有唯一一个
    • 多级继承
    • 一个父类可以有多个子类

      2.2 继承的访问控制

  • 三种重名的变量使用

    • 局部变量:直接使用 num
    • 本类成员变量: this.num
    • 父类成员变量: super.num
  • 成员变量的访问Fu zi = new Zi() 优先访问 Fu 类的成员变量
  • 成员方法的访问Fu zi = new Zi() 优先访问 Zi 类的成员方法
  • 构造方法的访问特点

    • 子类的构造方法中有一个默认隐含的 super() 调用
    • 子类构造可以通过 super 关键字来调用父类重载构造(此处 super() 即为父类的同名构造函数)
    • super 的父类构造调用,必须是子类构造方法的第一条语句。
    • 只有子类构造方法可以调用父类构造方法

      2.3 方法重写

      1.重写和重载的区别
  • 重写:方法的名称一样,参数列表也一样

  • 重载:方法的名称一样,但参数列表不一样

2.方法重写注意事项

  • 必须保证父子类方法名称相同,参数列表也相同
  • 使用 @Override 写在方法前面用来检测是不是有效的正确覆盖重写
  • 子类的返回值必须 小于等于 父类方法的返回值范围
  • 子类方法的权限必须 大于等于 父类方法的权限修饰符( public > protected > (default) > private) (注意, (default) 代表关键字留空)

    2.4 super & this

    1.super的三种用法

  • 在子类的成员方法中,访问父类的成员变量

  • 在子类的成员方法中,访问父类的成员方法
  • 在子类的构造方法中,访问父类的构造方法

2.this的三种用法

  • 在本类成员访问中,访问本类成员变量
  • 在本类成员方法中,访问本类另一个成员方法
  • 在本类的构造方法中,访问本类的另一个构造方法

    • this调用也必须是构造方法的第一个语句
    • super与this不可以同时使用
      1. public class Person{
      2. String name;
      3. Person(){
      4. this("Musou");
      5. }
      6. Person(String name){
      7. this.name = name;
      8. }
      9. }

      2.5 抽象类

  • 抽象方法:方法本身无具体实现,但方法有其存在的必要性(如计算图形面积的方法,动物进食的方法)

    1. public abstract class Animal {
    2. public abstract void eat(); //抽象方法
    3. }
  • 如何创建抽象类和抽象方法

    • 不能直接 new 抽象类对象
    • 必须用一个子类来继承抽象父类
    • 子类必须覆盖重写抽象父类当中所有的抽象方法
  • 注意事项
    • 抽象类不能直接创建对象
    • 抽象类可以有构造方法,是供子类创建对象时初始化父类成员使用的
    • 抽象类中不一定包含抽象方法,但有抽象方法的一定是抽象类
    • 没有抽象方法的抽象类也不能直接创建对象
    • 抽象类子类必须覆盖重写抽象父类当中所有的抽象方法,除非该子类也是抽象类

      3 接口

      接口是多个类的公共规范,是一种引用数据类型

3.1 接口的定义

接口定义的方法public interface 接口名称{}
接口包含的内容

  • Java7: 常量;抽象方法
  • Java8新增:默认方法;静态方法
  • Java9: 私有方法

    3.2 接口的抽象方法

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

  • 注意事项
    • 抽象方法的修饰符是固定的 public abstract
    • 这两个关键字修饰符,可以选择性地省略(省略一个或全部)
  • 接口的使用
    • 接口不能直接使用,必须有一个“实现类”来“实现”该接口: public class 实现类名称 implements 接口名称{}
    • 接口的实现类必须覆盖重写(实现)接口中所有的抽象方法
    • 创建实现类的对象,进行使用
  • 注意事项

    • 如果实现类并没有覆盖重写接口中的所有抽象方法,那这个实现类必须是抽象类

      3.3 接口的默认方法

  • 格式 public default 返回值类型(参数列表){方法体}

  • 接口当中的默认方法,可以解决接口升级的问题
  • 注意事项

    • 接口的默认方法,可以通过接口实现类对象直接调用
    • 接口的默认方法,也可以被接口的实现类覆盖重写

      3.4 接口的静态方法

  • 格式 public static 返回值类型 方法名称(参数列表){方法体};

  • 注意事项

    • 不能通过接口实现类的对象来调用接口当中的静态方法
    • 而应当通过接口名称直接调用其中的静态方法

      3.5 接口的私有方法(Java9)

  • 应用场景:需要抽取一个共有方法,用来解决两个默认方法之间重复代码的问题,但是这个共有方法不应该让实现类使用,而应该是私有化的

  • 普通私有方法 private 返回值类型 方法名称(参数列表){方法体}
  • 静态私有方法 private static 返回值类型 方法名称(参数列表){方法体}

    3.6 接口的常量

  • 格式 public static final 数据类型 常量名称 = 数据值;

  • 可以省略三个关键字修饰符
  • 常量必须进行初始化
  • 常量的命名规则:完全大写字母,使用下划线进行分割

    3.7 接口的继承

  • 使用接口的注意事项

    • 接口没有静态代码块和构造方法
    • 一个类的直接父类是唯一的,但是一个类可以同时实现多个接口
    • 如果实现类所实现的多个接口当中,存在重复的抽象方法,那么只需覆盖重写一次即可
    • 如果实现类没有覆盖重写所有接口中的所有抽象方法,那么实现类必须是一个抽象类
    • 如果实现类所实现的多个接口中,存在冲突的默认方法,那么一定要对冲突的默认方法进行覆盖重写
    • 一个类如果直接父类中的方法与接口中的默认方法冲突,那么优先使用父类的方法
  • 接口与接口之间,是可以多继承的

    • 多个父接口中的抽象方法可以重复
    • 如果多个父接口中的默认方法重复,子接口必须进行默认方法的覆盖重写

      4 多态

      4.1 多态的格式

  • 代码中体现多态性的方法:父类引用指向子类对象

  • 格式 父类名称 对象名 = new 子类名称() 或者 接口名称 对象名 = new 实现类名称()
  • 使用多态的好处

    • 能有什么好处。。。。。。
    • 好像可以规范代码

      4.2 多态成员变量

  • 直接通过对象名称访问成员变量:看等号左边是谁,就优先用谁,没有则向上找

  • 间接通过成员方法访问成员变量:看该方法属于谁,就优先用谁,没有则向上找

    4.3 多态成员方法

  • 成员方法的访问规则:看 new 的是谁,就优先用谁,没有则向上找

  • 区别

    • 成员变量:编译看左边,运行看左边
    • 成员方法:编译看左边,运行看右边

      4.4 对象的转型

      向上转型

  • 多态写法: ParentClass obj = new ChildClass();

  • 含义:右侧创建一个子类对象,把它当作父类来看待使用
  • 向上转型一定是安全的,因为小范围一定包含于大范围
  • 弊端:对象一旦向上转型为父类,那么就无法调用子类原本特有的内容

    向下转型

  • 对象的向下转型,其实就是一个还原的动作

  • 格式 ChildClass obj = (ChildClass)parentObj;
  • 含义:将父类对象还原成为子类对象
  • 注意:向下转型必须【还原】成为原本的对象类

    类型判断

  • 使用 instanceof 关键字

  • 格式 对象名 instanceof 类名称 会返回一个布尔值

    5 内部类

    5.1 final关键字

  • 修饰类

    • public final class 类名称{}
    • 太监类,当前这个类不能有任何子类
  • 修饰成员变量
    • 由于成员变量具有默认值,所以使用 final 后必须手动赋值
    • 要么直接赋值,要么通过构造方法赋值
  • 修饰成员方法
    • 修饰符 final 返回值类型 方法名称(参数列表){}
    • 该方法不可被覆盖重写
  • 修饰局部变量

    • final int num = 100;
    • 一次赋值,终生不变
      • 对于基本类型,不可变指数据值不再发生改变
      • 对于引用类型,不可变指地址值不再发生改变

        5.2 权限修饰符

        | | public | protected | (default) | private | | —- | —- | —- | —- | —- | | 同一个类 | ☑️ | ☑️ | ☑️ | ☑️ | | 同一个包 | ☑️ | ☑️ | ☑️ | ✖️ | | 不同包的子类 | ☑️ | ☑️ | ✖️ | ✖️ | | 不同包非子类 | ☑️ | ✖️ | ✖️ | ✖️ |
  • 权限修饰符小结

    • public > protected > (default) > private
    • 定义一个类时,权限修饰符规则
      • 外部类:public/(default)
      • 成员内部类:public/protected/(default)/private
      • 局部内部类:什么也不能写

        5.3 内部类的概念与定义

  • 如果一个事物的内部包含另一个事物,那么称一个类包含一个内部类

  • 内部类分为

    • 成员内部类
    • 局部内部类(包含匿名内部类)

      成员内部类

  • 成员内部类的定义

    1. public class Body{
    2. public class Heart{
    3. public void beat(){
    4. System.out.println("My heart beats.");
    5. }
    6. ...
    7. }
    8. public void methodBody(){
    9. Heart heart = new Heart();
    10. heart.beat();
    11. }
    12. ...
    13. }

    注意:内用外,随意访问;外用内,必须借助内部类对象

  • 成员内部类的使用

    1. public class Main(){
    2. public static void main(String[] args){
    3. //间接方式:在外部类的方法中使用内部类,然后main只是调用外部类的方法
    4. Body body = new Body();
    5. body.methodBody();
    6. //直接方式
    7. Body.Heart heart = new Body().new Heart();
    8. heart.beat();
    9. }
    10. }
  • 内部类的同名变量访问 ```java public class Outer { int num = 30; public class Inner{

    1. int num = 20;
    2. public void method(){
    3. int num = 10;
    4. System.out.println(num); // 局部变量,就近原则
    5. System.out.println(this.num); // 使用内部类成员变量
    6. System.out.println(Outer.this.num); // 使用外部类成员变量
    7. }

    } }

  1. <a name="ahgRq"></a>
  2. ### 局部内部类
  3. ```java
  4. public class Outer {
  5. public void methodOuter(){
  6. class LocalInner{
  7. int num = 10;
  8. public void methodInner(){
  9. System.out.println(num);
  10. }
  11. }
  12. LocalInner inner = new LocalInner();
  13. inner.methodInner();
  14. }
  15. }
  • 局部内部类如果希望访问所在方法的局部变量,那么这个局部变量必须是【有效final的】
  • 从Java8开始,只要局部变量事实不变,那么 final 关键字可以省略(跟生命周期相关)

    匿名内部类

    匿名内部类也是局部内部类中的一种

  • 如果接口的实现类(或者父类的子类)只需要使用唯一的一次,那么可以省略掉该类的定义,而改为使用 匿名内部类

  • 匿名内部类的定义格式

    1. //接口名称 对象名 = new 接口名称(){
    2. // 覆盖重写所有的抽象方法
    3. //}
    4. MyInterface obj = new MyInterface(){
    5. @Override
    6. public void method(){
    7. System.out.println("匿名内部类");
    8. }
    9. };

    6 包装类

    6.1 概念

  • 包装类 :基本类型没有对应的方法来操作基本类型的数据,因此可以使用类进行包装,在类中定义操作基本类型的方法

  • 包装规则

    • byte —-> Byte
    • short —-> Short
    • int —-> Integer
    • long —-> Long
    • float —-> Float
    • double —-> Double
    • char —-> Character
    • boolean —-> Boolean

      6.2 装箱与拆箱

      基本类型与对应的包装类对象之间来回转换的过程
  • 装箱 :从基本类型转换为对应的包装类对象

  • 拆箱 :从包装类对象转换为对应的基本类型 ```java //装箱 Integer i = new Integer(4); //使用构造方法(已过时) Integer j = new Integer(“100”); //使用构造方法 Integer k = Integer.valueOf(4); //使用静态方法 Integer w = Integer.valueOf(“100”);

//拆箱 int ii = i.intValue(); int jj = j.intValue();

  1. > Java5开始,装箱与拆箱动作可以自动完成
  2. <a name="anr18"></a>
  3. ##
  4. <a name="tvA1v"></a>
  5. ## 6.3 基本类型与字符串相互转换
  6. - 基本类型 ===> 字符串(String)
  7. - 基本类型值 + ""
  8. - **包装类** 的静态方法 `toString` : `static String toString(int i)`
  9. - **String类** 的静态方法 `valueOf` : `static String valueOf(int i)`
  10. - 字符串 ===> 基本类型
  11. - 使用包装类的静态方法parseXXX: `static double parseDouble(String s)`
  12. <a name="AcMji"></a>
  13. # 7 泛型
  14. > ArrayList集合在定义时不知道集合中会存储什么类型的数据,此时可以使用使用泛型
  15. **使用泛型的好处**
  16. - 集合若不使用泛型,默认的类型是 `Object` 类型,可以存储任意类型的数据,这样不安全,会引发异常(例如不能使用子类特有的方法,必须得向下转型,很麻烦)
  17. - 使用泛型,避免了类型转换的麻烦
  18. - 使用反省,把运行期异常提升到了编译期
  19. <a name="FpJoz"></a>
  20. ## 7.1 含泛型的类
  21. ```java
  22. public class GenericClalss<E>{
  23. private E name;
  24. public E getName(){
  25. return name;
  26. }
  27. public void setName(E name){
  28. this.name = name;
  29. }
  30. }

7.2 含泛型的方法

  • 泛型定义在方法的修饰符和返回值类型之间 ```java package Generic;

public class GenericMethod { public void method01(M m){ System.out.println(m); } public static void method02(S s){ System.out.println(s); } }

  1. <a name="XY37m"></a>
  2. ## 7.3 含泛型的接口
  3. ```java
  4. package Generic;
  5. public interface GenericInterface<T>{
  6. public abstract void method01(T i);
  7. }
  • 第一种实现方式 ```java package Generic;

public class GenericInterfaceImpl1 implements GenericInterface{ @Override public void method01(String s){ System.out.println(s ); } }

  1. - 第二种实现方式
  2. ```java
  3. package Generic;
  4. public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
  5. @Override
  6. public void method01(I i) {
  7. System.out.println(i);
  8. }
  9. }

7.4 泛型通配符

  • 不知道使用什么类型来接收时,可以使用?, 其中?表示通配符
  • 此时只能接收数据,不能往该集合中存储数据
  • 泛型没有继承概念,所以无法使用向上转型来接收参数 ```java package API;

import java.util.ArrayList; import java.util.Iterator;

public class DemoAsterisk { public static void main(String[] args) { ArrayList list1 = new ArrayList<>(); list1.add(1); list1.add(2); ArrayList list2 = new ArrayList<>(); list2.add(“Hello”); list2.add(“World”); printArray(list1); printArray(list2); } public static void printArray(ArrayList<?> list){ // for (int i = 0; i < list.size(); i++) { // System.out.println(list.get(i)); // } Iterator<?> it = list.iterator(); while(it.hasNext()){ System.out.println(it.next()); } } }

  1. - **泛型的上限限定** `? extends E` 代表使用的泛型只能是E类型的子类/本身
  2. - **泛型的下限限定** `? super E` 代表使用的泛型只能是E类型的父类/本身
  3. ```java
  4. package API;
  5. import java.util.ArrayList;
  6. import java.util.Collection;
  7. public class DemoAsterisk2 {
  8. public static void main(String[] args) {
  9. Collection<Integer> list1 = new ArrayList<>();
  10. Collection<String> list2 = new ArrayList<>();
  11. Collection<Number> list3 = new ArrayList<>();
  12. Collection<Object> list4 = new ArrayList<>();
  13. getElement1(list1);
  14. getElement1(list2); //报错
  15. getElement1(list3);
  16. getElement1(list4); //报错
  17. getElement2(list1); //报错
  18. getElement2(list2); //报错
  19. getElement2(list3);
  20. getElement2(list4);
  21. }
  22. private static void getElement1(Collection<? extends Number> list) {
  23. }
  24. private static void getElement2(Collection<? super Number> list) {
  25. }
  26. }

8 枚举