九.面向对象的思想(五)

九.面向对象的思想(五)

1.代码块

代码块又称为初始化块,属于类中的成员(即 是类的一部分),类似于方法,将逻辑语句封装在方法体中,通过{}包围起来。

但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类的显式调用,而是加载类时,或创建对象时隐 式调用。

代码块语法

【修饰符】{

代码

};

说明注意:

1)修饰符可选,要写的话,也只能写static

2)代码块分为两类,使用static修饰的叫静态代码块,没有static修饰的,叫普通代码块/非静态代码块。

3)逻辑语句可以任何逻辑语句(输入,输出,方法调用,循环,判断等)

4);号可以写上,也可以忽略

代码块的好处:

1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化操作

2)场景:如果多个构造器中都有重复的语句,可以抽取到代码块中,提高代码的重用性。

使用注意事项

1)static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,没创建一个对象,就执行。

2)类什么时候被加载

1.创建对象实例时

2.创建对象的子类对象实例,父类也会被加载

3.使用类的静态成员时(静态属性,静态方法)

3)普通的代码块,在创建对象实例时,会被隐式的调用。

被创建以西,就会调用一次。

如果只是是哟了那个类的静态成员时,普通代码块并不会执行

 

创建一个子类对象时,他们的静态代码块,静态代码块,普通代码块,普通属性初始化,构造方法的调用顺序

1.父类的静态代码块和静态属性(优先级一样,按定义顺序执行)

2.子类的静态代码块和静态属性(优先级一样,定义顺序执行)

3.父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

4.父类的构造方法

5.子列的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)

5.子类的构造方法

 

2.单例设计模式

1.单例设计模式,就是采取一定的方法保证整个的软件系统中,对某个类只能存在一个对象的实例,并且该列只提供一个取得其对象实例的方法

2.单例设计模式有两种方式:1)饿汉式 2)懒汉式

单例设计模式的两种实现方式:
一、懒汉式:随着类的加载在内存中对象为null,当调用 getInstance 方法时才创建对象(延迟加载)
二、饿汉式:随着类的加载直接创建对象(推荐开发中使用)
单例设计模式的实现步骤:
1.保证一个类只有一个实例,实现方式:构造方法私有化
2.必须要自己创建这个实例,实现方式:在本类中维护一个本类对象(私有,静态)
3.必须向整个程序提供这个实例,实现方式:对外提供公共的访问方式(getInstance方法,静态)
懒汉式实现如下:
class Single{
   private Single(){}
   private static Single s1 = null;
   public static Single getInstance(){
       if(s1 == null){
      s1 = new Single();
}
return s1;
}
}
饿汉式实现如下:
class Single2{
   private Single2(){}
   private static Single2 s = new Single2();
   public static Single getInstance(){
  return s;
}
}

 

饿汉式和懒汉式的区别

1).二者最主要的区别子啊与创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。

2)饿汉式不存在线程安全问题,懒汉式窜在线程安全问题。

3)饿汉式存在浪费资源的可能,懒汉式是使用才创建,就不存在这个问题。

3.final关键字

final可以修饰类,属性,方法和局部变量。

使用情况

在某些情况下,程序员可能有以下需求,就会使用到final:

1)当不希望类被继承时,可以使用final修饰。

2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。

3)当不希望类的某个属性的值被修改时,可以用final关键字修饰。

4)当不希望某个局部变量被修改,可以使用final修饰。

 

final使用的注意事项

1)final修饰的属性又叫常量,一般用大写字母和下划线来命名

2)final修饰的属性在定义是,必须赋初始值,并且以后不能再修改,赋值可以在以下位置之一:

1.定义是:如public final double TAX_RATE=0.08;

2.在构造器中

3.在代码块中

3)如果final修饰的属性是静态的,则初始化的位置只能是

1.定义时

2.在静态代码块中,不能在构造器中赋值。

4)final类不能继承,但是可以实例化对象

5)如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。

6)一般来说,如果一个类已经是final类了,就没有比喻哦啊再将方法修饰成finall

7)final和static往往搭配使用,效率更高,不会导致类加载底层编译器做了优化处理。

8)包装类(Integer,Double,Float,Boolean等都是final),String也是final类。

 

4.抽象类

当父类的某些方法,需要声明,但是又不能确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类

public class Abstract01 {
   public static void main(String[] args) {
  }
}

abstract class Animal {
   private String name;
   public Animal(String name) {
  this.name = name;
  }
   //思考:这里 eat 这里你实现了,其实没有什么意义
   //即: 父类方法不确定性的问题
   //===> 考虑将该方法设计为抽象(abstract)方法
   //===> 所谓抽象方法就是没有实现的方法
   //===> 所谓没有实现就是指,没有方法体
   //===> 当一个类中存在抽象方法时,需要将该类声明为 abstract 类
   //===> 一般来说,抽象类会被继承,有其子类来实现抽象方法. // public void eat() {
   // System.out.println("这是一个动物,但是不知道吃什么..");
   // }
public abstract void eat() ;
}
抽象类的介绍

1)用abstract关键字来修饰一个类时,这个类就叫抽象类

访问修饰符 abstract 类名{

}

2)用abstract关键字来修饰一个方法时,这个方法就是抽象方法

访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体

3)抽象类的价值更多作用在于设计,是设计者设计好后,让子类继承并实现抽象类()

抽象类的使用注意事项

1)抽象类不能被实例化

2)抽象类不一定要包括abstract方法。也就是说,抽象类可以没有abstarct方法

3)一旦类包含了abstract方法,则这个类必须声明为abstract

4)abstract只能修饰类和方法,不能修饰属性和其他的。

5)抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法,构造器,静态属性等等

6)抽象方法不能有主体,即不能实现。

7)如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。

8)抽象方法不能使用private,final和static来修饰,因为这些关键字都是和重写相违背的。

 

5.接口

基本介绍

接口解释给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。

 

语法:

interface 接口名{

//属性

//抽象方法

}

class 类名 implements 接口 {

自己的属性;

自己的方法;

必须实现的接口的抽象方法

}

接口是更加抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体。接口体现了程序的多态和高内聚低耦合的设计思想。

public interface DBInterface { //项目经理
  public void connect();//连接方法
  public void close();//关闭连接
}


//A 程序
public class MysqlDB implements DBInterface {
  @Override
  public void connect() {
  System.out.println("连接 mysql")
  }
  @Override
  public void close() {
  System.out.println("关闭 mysql");
  }
}


//B 程序员连接 Oracle
public class OracleDB implements DBInterface{
  @Override
  public void connect() {
  System.out.println("连接 oracle");
  }
  @Override
  public void close() {
  System.out.println("关闭 oracle");
  }
  }
   
   
  public class Interface03 {
      public static void main(String[] args) {
          MysqlDB mysqlDB = new MysqlDB();
          t(mysqlDB);
          OracleDB oracleDB = new OracleDB();
          t(oracleDB);
      }
  public static void t(DBInterface db) {
      db.connect();
      db.close();
  }
}
接口使用的注意事项:

1)接口不能被实例化

2)接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰;

3)一个普通类实现接口,就必须将该接口的所有方法都实现。

4)抽象类实现接口,可以不用实现接口的方法。

5)一个类同时可以实现多个接口

6)接口中的属性,只能是final的,而且是public static final修饰符。

7)接口中属性的访问形式:接口名.属性名

8)接口不能继承其他的类,但可以继承多个别的接口

interface A extends B,C{}

9)接口的修饰符只能是public和默认,这点和类的修饰符是一样的。

 

6.内部类

如果定义类在局部位置(方法或代码块):(1)局部内部类 (2)匿名内部类

定义在成员位置:(1)成员内部类 (2)静态内部类

基本介绍:

一个类的内部又完整的嵌套了另一个类的结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类。是我们类的第五大成员【类的五大成员:属性,方法,构造器,代码块,内部类】,内部类最大的特点解释可以直接访问私有属性,并且可以体现类与类之间的包含关系。

基本语法:
class Outer{  //外部类
class Inner{ //内部类
}
}
class Other{ //外部其他类
}
内部类的分类

定义在外部类局部位置上(比如方法内):

1)局部内部类(有类名)

2)匿名内部类(没有类名)

 

定义在外部类的成员位置上

1)成员内部类(没用static修饰)

2)静态内部类(使用static修饰)

 

局部内部类

局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。

1.可以直接访问外部类的所有成员,包括私有的。

2.不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final

3.作用域:仅仅是在定义它的方法或代码块中。

4.外部类访问局部内部类的成员需要在作用域内,创建对象再访问。

5.如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。

 

public class LocalInnerClass {//
   public static void main(String[] args) {
       //演示一遍
       Outer02 outer02 = new Outer02();
       outer02.m1();
       System.out.println("outer02 的 hashcode=" + outer02);
  }
}
class Outer02 {//外部类
   private int n1 = 100;
   private void m2() {
  System.out.println("Outer02 m2()");
  }//私有方法
   public void m1() {//方法
  //1.局部内部类是定义在外部类的局部位置,通常在方法
  //3.不能添加访问修饰符,但是可以使用 final 修饰
  //4.作用域 : 仅仅在定义它的方法或代码块中
  final class Inner02 {//局部内部类(本质仍然是一个类)
  //2.可以直接访问外部类的所有成员,包含私有的
           private int n1 = 800;
           public void f1() {
           //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1 和 m2()
           //7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
           // 使用 外部类名.this.成员)去访问
           // Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象
               System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1);
               System.out.println("Outer02.this hashcode=" + Outer02.this);
               m2();
          }
      }
  //6. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可
       Inner02 inner02 = new Inner02();
       inner02.f1();
  }
}
匿名内部类:

(1)本质是类 (2)内部类(3)该类没有名字(4)同时还是一个对象

说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名

 

基本语法:

new 类或接口(参数列表){

类体

};

 

/**
* 演示匿名内部类的使用
*/
public class AnonymousInnerClass {
   public static void main(String[] args) {
       Outer04 outer04 = new Outer04();
       outer04.method();
  }
}
class Outer04 { //外部类
private int n1 = 10;//属性
public void method() {//方法
//基于接口的匿名内部类
//老韩解读
//1.需求: 想使用 IA 接口,并创建对象
//2.传统方式,是写一个类,实现该接口,并创建对象
//3.需求是 Tiger/Dog 类只是使用一次,后面再不使用
//4. 可以使用匿名内部类来简化开发
//5. tiger 的编译类型 ? IA
//6. tiger 的运行类型 ? 就是匿名内部类 Outer04$1
       /*
      我们看底层 会分配 类名 Outer04$1
           class Outer04$1 implements IA {
           @Override
           public void cry() {
          System.out.println("老虎叫唤...");
           }
       }
       */
//7. jdk 底层在创建匿名内部类 Outer04$1,立即马上就创建了 Outer04$1 实例,并且把地址
// 返回给 tiger
//8. 匿名内部类使用一次,就不能再使用
IA tiger = new IA() {
           @Override
           public void cry() {
           System.out.println("老虎叫唤...");
}
};
System.out.println("tiger 的运行类型=" + tiger.getClass());
       tiger.cry();
       tiger.cry();
       tiger.cry();
       // IA tiger = new Tiger();
       // tiger.cry();
       //演示基于类的匿名内部类
       //分析
       //1. father 编译类型 Father
       //2. father 运行类型 Outer04$2
       //3. 底层会创建匿名内部类
       /*
           class Outer04$2 extends Father{
               @Override
               public void test() {
              System.out.println("匿名内部类重写了 test 方法");
               }
           }
       */
       //4. 同时也直接返回了 匿名内部类 Outer04$2 的对象
       //5. 注意("jack") 参数列表会传递给 构造器
       Father father = new Father("jack"){
           @Override
           public void test() {
               System.out.println("匿名内部类重写了 test 方法");
          }
};
       System.out.println("father 对象的运行类型=" + father.getClass());//Outer04$2
       father.test();
  //基于抽象类的匿名内部类
       Animal animal = new Animal(){
      @Override
           void eat() {
                   System.out.println("小狗吃骨头...");
          }
};
animal.eat();
}
}
interface IA {//接口
public void cry();
}
//class Tiger implements IA {
//
// @Override
// public void cry() {
// System.out.println("老虎叫唤...");
// }
//}
//class Dog implements IA{
// @Override
// public void cry() {
// System.out.println("小狗汪汪...");
// }
//}
class Father {//类
   public Father(String name) {//构造器
       System.out.println("接收到 name=" + name);
  }
   public void test() {//方法
  }
}
abstract class Animal { //抽象类
abstract void eat();
}
成员内部类

成员内部类是定义在外部类的成员位置,并且没有static修饰。

public class MemberInnerClass01 {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,使用成员内部类的三种方式
// 第一种方式
// outer08.new Inner08(); 相当于把 new Inner08()当做是 outer08 成员
// 这就是一个语法,不要特别的纠结.
       Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
// 第二方式 在外部类中,编写一个方法,可以返回 Inner08 对象
Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
inner08Instance.say();
}
}
class Outer08 { //外部类
private int n1 = 10;
public String name = "张三";
private void hi() {
System.out.println("hi()方法...");
}
//1.注意: 成员内部类,是定义在外部内的成员位置上
//2.可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
public class Inner08 {//成员内部类
          private double sal = 99.8;
          private int n1 = 66;
          public void say() {
              //可以直接访问外部类的所有成员,包含私有的
              //如果成员内部类的成员和外部类的成员重名,会遵守就近原则. //,可以通过 外部类名.this.属性 来访问外部类的成员
              System.out.println("n1 = " + n1 + " name = " + name + " 外部类的 n1=" + Outer08.this.n1);
              hi();
          }
}
//方法,返回一个 Inner08 实例
public Inner08 getInner08Instance(){
return new Inner08();
}
//写方法
public void t1() {
          //使用成员内部类
          //创建成员内部类的对象,然后使用相关的方法
       Inner08 inner08 = new Inner08();
       inner08.say();
System.out.println(inner08.sal);
}
}

 

静态内部类

静态内部类是定义在外部类的所有成员位置,并且有static修饰

public class StaticInnerClass01 {
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
outer10.m1();
//外部其他类 使用静态内部类
//方式 1
//因为静态内部类,是可以通过类名直接访问(前提是满足访问权限)
Outer10.Inner10 inner10 = new Outer10.Inner10();
inner10.say();
       //方式 2
       //编写一个方法,可以返回静态内部类的对象实例. Outer10.Inner10 inner101 = outer10.getInner10();
System.out.println("============");
inner101.say();
Outer10.Inner10 inner10_ = Outer10.getInner10_();
System.out.println("************");
inner10_.say();
}
}
class Outer10 { //外部类
private int n1 = 10;
private static String name = "张三";
private static void cry() {}
//Inner10 就是静态内部类
//1. 放在外部类的成员位置
//2. 使用 static 修饰
//3. 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问非静态成员
//4. 可以添加任意访问修饰符(public、protected 、默认、private),因为它的地位就是一个成员
//5. 作用域 :同其他的成员,为整个
static class Inner10 {
private static String name = "aaa";
public void say() {
//如果外部类和静态内部类的成员重名时,静态内部类访问的时,
//默认遵循就近原则,如果想访问外部类的成员,则可以使用 (外部类名.成员)
System.out.println(name + " 外部类 name= " + Outer10.name);
cry();
}
}
public void m1() { //外部类---访问------>静态内部类 访问方式:创建对象,再访问
Inner10 inner10 = new Inner10();
inner10.say();
}
public Inner10 getInner10() {
return new Inner10();
}
public static Inner10 getInner10_() {
return new Inner10();
}
}

 

posted @ 2021-11-10 18:06  brysjs  阅读(198)  评论(0)    收藏  举报