Part1 面向对象(下)

一、内部类

1.内部类的概念

内部类是一种特殊的类,指的是定义在一个类内部的类,内部类依附于外部类。实际开发中,为了方便地使用外部类的相关属性和方法,这时候我们通常会定义一个内部类。内部类可以使用public、default、protected、private和static修饰,而外部顶级类(我们前面所写的这些类)只能用public、default修饰,非静态内部类不能拥有静态成员。
Day7 - 图1
四种类里非静态内部类偶尔用,其余三种用的很少,了解语法即可。

2.创建内部类

内部类依附于外部类,在创建时需要先创建外部类,在创建内部类。

  1. 外部类.内部类 引用变量 = new 外部类().new 内部类();
  1. class Outer{
  2. private int age = 1;
  3. private void showOuter(){
  4. System.out.println("我是外部类中的方法");
  5. }
  6. //内部类
  7. class Inner{
  8. private int age = 2;
  9. void showInner(){
  10. System.out.println("我是内部类中的方法");
  11. System.out.println(age);
  12. System.out.println(Outer.this.age);//当内部类和外部类成员名相同时,可以通过Outer.this.成员名调用
  13. showOuter();//内部类可以直接使用外部类的方法
  14. }
  15. }
  16. }
  17. public class Test {
  18. public static void main(String[] args) {
  19. Outer.Inner p = new Outer().new Inner();//创建内部类对象
  20. p.showInner();//使用内部类方法
  21. }
  22. }
  23. //我是内部类中的方法
  24. //2
  25. //1
  26. //我是外部类中的方法
  1. class Face{
  2. private String shape = "国字脸";
  3. class Nose{
  4. private String shape = "高鼻梁";
  5. public void breath(){
  6. System.out.print("鼻子长在了一张" + Face.this.shape + "上");
  7. System.out.println("呼吸");
  8. }
  9. }
  10. class Ear{
  11. }
  12. class Eye{
  13. }
  14. }
  15. public class Test {
  16. public static void main(String[] args) {
  17. Face.Nose p = new Face().new Nose();
  18. p.breath();
  19. }
  20. }
  21. //鼻子长在了一张国字脸上呼吸

内部类是编译时的概念,在编译之后,是完全不同的两个类。比如上面的代码编译后,会生成Face.class,Face$Nose.class,Face$Ear.class,Face$Eye.class四个class文件,所以内部类是相对独立的一种存在,其成员变量、方法可以和外部类一样。

3.内部类的作用

  • 提供更好地封装。只能由外部类访问,不允许同一个包中的其他类访问,隐藏在外部类之内。
  • 内部类可以直接访问外部类的私有属性,因为内部类被当成其外部类成员,同一个类的成员之间可以相互访问。但外部类不能访问内部类的属性。
  • 匿名内部类适用于创建那些仅需要使用一次的类。

    4.非静态内部类

    外部类里使用非静态内部类和平时使用其他类没什么不同。

  • 非静态内部类对象必须寄存在外部类对象里。因此,如果有一个非静态内部类对象,那么一定存在对应的外部类对象,非静态内部类对象作为外部类对象的一个成员。

  • 非静态内部类可以直接访问外部类成员,而外部类不能直接访问内部类成员。
  • 非静态内部类不能有静态方法、静态属性和静态初始化块。
  • 非静态内部类成员变量访问要点: | 内部类里方法的局部变量 | 变量名 | | —- | —- | | 内部类属性 | this.变量名 | | 外部类属性 | 外部类名.this.变量名 |

5.静态内部类

  • 定义方式:

    1. static class name{
    2. 类体
    3. }
  • 使用要点:

静态内部类可以访问外部类的静态成员,但不能访问非静态成员。静态内部类看作外部类的一个静态成员。

6.匿名内部类

适合那种只需要使用一次的类。比如键盘监听操作,在安卓、awt、swing开发中常见。

  • 定义格式:

    1. new 实现接口() | 父类构造器(实参列表){
    2. //匿名内部类的类体
    3. }

    匿名内部类必须继承一个父类或实现一个接口

  • 匿名内部类的规则:

1)匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建一个匿名内部类对象。
2)匿名内部类不能定义构造器,由于匿名内部类没有类名,所以无法定义构造器,但可以定义初始化块,通过初始化块完成构造器需要完成的事。
最常用的创建匿名内部类的方式是需要创建某个接口类型的对象:

  1. interface Product{
  2. int getPrice();
  3. }
  4. public class Test {
  5. public void test(Product p){
  6. System.out.println("购买一个产品需要花费" + p.getPrice() + "元");
  7. }
  8. public static void main(String[] args) {
  9. Test t = new Test();
  10. //调用test方法时,需要传入一个Product参数
  11. //此处传入其匿名实现类的实例
  12. t.test(new Product() {
  13. public int getPrice() {
  14. return 100;
  15. }
  16. });
  17. }
  18. }
  19. //购买一个产品需要花费100元

7.局部内部类

定义在方法内部的类,作用域仅限于本方法,被称为局部内部类。局部内部类的使用主要是为了解决一些复杂的问题,想创建一个类来辅助我们解决问题,但又不希望这个类是公共可用的,就产生了局部内部类。局部内部类和成员内部类一样被编译,不过它的作用域发生了改变,只可用在这个方法里使用,出了该方法就失效。
局部内部类在实际开发中用的非常少,简单了解即可。

  1. class A{
  2. void show(){
  3. //局部内部类,只能在该方法里使用
  4. class Inner{
  5. public void fun(){
  6. System.out.println("Helloworld");
  7. }
  8. }
  9. new Inner().fun();
  10. }
  11. }
  12. public class Test {
  13. public static void main(String[] args) {
  14. new A().show();
  15. }
  16. }

二、枚举类

在某些情况下,一个类的对象是有限而且固定的,比如季节类,它只有4个对象。这种实例有限而且固定的类,在Java里被称为枚举类。使用枚举类可以使程序更加健壮,避免创建对象的随意性。

1.枚举类入门

Java使用enum关键字用以定义枚举类,枚举类是一种特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或者多个接口,也可以定义自己的构造器。一个Java源文件最多只能定义一个public访问权限的枚举类,且该Java源文件必须和该枚举类同名。

  • 枚举类和普通类的区别:

1)枚举类可以实现一个或多个接口,枚举类默认继承了java.lang.Enum类,而不是继承Object类,因此枚举类不能显式继承其他父类。
2)使用enum定义、非抽象的枚举类默认会使用final修饰。
3)枚举类的构造器只能使用private修饰,如果省略了该修饰符,默认使用private修饰。由于枚举类的所有构造器都是private的,每个子类都会调用父类的构造器,所以枚举类不能派生子类。
4)枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类不能产生实例。列出的实例会自动添加public static final修饰,无须显式添加。
5)枚举类默认提供了一个valus()方法,用来遍历所有的枚举值。

  1. enum Season{
  2. //在第一行显式列出枚举值
  3. SPRING, SUMMER, FALL, WINTER;
  4. }
  5. public class Test {
  6. public void judge(Season s){
  7. //switch语句里的表达式可以是枚举值
  8. switch (s){
  9. case SPRING:
  10. System.out.println("春暖花开");break;
  11. case SUMMER:
  12. System.out.println("夏日炎炎");break;
  13. case FALL:
  14. System.out.println("秋高气爽");break;
  15. case WINTER:
  16. System.out.println("冬日飘雪");break;
  17. }
  18. }
  19. public static void main(String[] args) {
  20. //枚举类默认提供一个valus()方法,返回该枚举类的所有实例
  21. for(var s : Season.values()){
  22. System.out.println(s);//实际使用的是枚举类的toString方法
  23. //System.out.println(s.toString());
  24. }
  25. //使用枚举类时,通过EnumClass.variable的形式来访问
  26. new Test().judge(Season.SPRING);
  27. }
  28. }
  29. //SPRING
  30. //SUMMER
  31. //FALL
  32. //WINTER
  33. //春暖花开

2.枚举类的方法

所有的枚举类都继承了java.lang.Enum类,可以直接是使用该类中的方法:

  • int compareTo(E o):该方法用于与指定枚举对象比较顺序,同一个枚举实例只能与相同类型的枚举实例进行比较。如果该枚举对象位于指定枚举对象之后,则返回正整数;如果该枚举对象位于指定枚举对象之前,则返回负整数,否则返回零。
  • String name():返回此枚举实例的名称,这个名称就是定义枚举时列出的所有枚举值之一。相比于使用这个方法,更倾向于使用toString方法,因为toString方法返回更加友好的名称。
  • String toString():返回枚举常量的名称,与name()方法相似,但toString更常用。
  • int ordinal():返回枚举值在枚举类中的索引值(即枚举值在枚举声明中的位置,第一个枚举值的索引值为0)

    3.枚举的使用

    当需要定义一组常量时可以使用枚举类型,尽量不要使用枚举的高级特性,事实上高级特性都可以通过普通类实现,没有必要引入枚举,增加程序的复杂性。

    三、数组

    四、常用设计模式

    1.单例模式

    2.工厂模式