九.面向对象的思想(五)
九.面向对象的思想(五)
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() {
