主要知识点:
- Object类
- 单例模式
- final关键字
- 抽象类
- 接口
- 内部类
- Object类
Object所有类的直接或者间接的父类,java认为所有的对象都具备一些基本的共性内容,这些内容可以不断的向上抽取,最终就抽取到了一个顶层的类中,该类中定义的就是所有对象都具备的功能。
1.boolean equals(Object obj):用于比较两个对象是否相等,其实内部比较的就是两个对象的地址。
而根据对象的不同,判断对象是否相同的具体内容也不一样,所以在定义类时,一般都会复写equals方法,建立本类特有的对象是否相同的依据。
public boolean equals(Object obj){ if(!(obj instanceof Person)) return false; Person p = (Person)obj; return this.age == p.age; }
2.String toString():将对象变成字符串;默认返回的格式:类名@哈希值 = getClass().getName()+‘@‘+Integer.toHexString(hashCode())
为了对象对应字符串的内容有意义,可以通过复写,建立类对象特有的字符串表现形式。
public String toString(){ return "person : "+age; }
3.Class getClass():获取任意对象运行时的所属字节码文件。反射的时候详细说。
4.int hashCode():返回该对象的哈希码值,支持此方法是为了提高哈希表的性能。
- 单例模式
解决的问题:保证一个类在内存中的对象唯一性。
比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中的数据,又要保证多个程序读到的是同一个配置文件,就需要该配置文件对象在内存中是唯一的。
Runtime()方法就是单例模式进行设计的。
如何保证对象的唯一性呢?
思想:1.不让其他程序创建该类对象。2.在本类中创建一个本类对象。3.对外提供方法,让其他程序获取这个对象。
步骤:
- 因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法创建该类对象。
- 就在类中创建一个本类对象。
- 定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
代码体现:
- 私有化构造函数
- 创建私有并静态的本类对象。
- 定义公有并静态的方法,返回该对象。
//饿汉式 class Single{ private Single(){} // 私有化构造函数。 private static Single s = new Single(); // 创建私有并静态的本类对象。 public static Single getInstance(){ // 定义公有并静态的方法,返回该对象。 return s; } } //懒汉式:延迟加载方式。 class Single2{ private Single2(){} private static Single2 s = null; public static Single2 getInstance(){ f(s==null) s = new Single2(); return s; } }
- final关键字
- final可以修饰类方法变量。
- final类不可以被继承,但是可以继承其他类。
- final修饰方法不可以被复写,但是可以复写父类方法。
- final修饰的变量称为常量,这些变量只能赋值一次。
- 内部类在局部时,只可以访问被final修饰的变量。
- final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变。
- 抽象类
当描述事物时,没有足够的信息对事物进行描述,那么该描述对应的类就是一个抽象类。
狗:
行为:吼叫
狼:
行为:吼叫
狼和狗具备着共性功能,可以抽取,
它们都是犬科中的一种。而吼叫是犬科中的基本功能。
abstract class 犬科 { static abstract void 吼叫(); } class 狗 extends 犬科 { void 吼叫() { System.out.println("汪汪"); } } class 狼 extends 犬科 { void 吼叫() { System.out.println("嗷嗷"); } }
当我们编写一个类时,我们往往会为了该类定义一些方法,这些方法是为了描述该类的行为方式,那么这些方法都有具体的方法体。但是,有的时候父类只知道子类应该包含怎么样的方法,但是无法准确的知道子类如何实现该方法。这时就用到了抽象类。
抽象类的特点:
1.抽象方法只能定义在抽象类中,抽象类和抽象方法必须要用abstract关键字修饰(可以描述类和方法,不可以描述变量)
2.抽象方法只能定义方法声明,并不定义方法实现。
3.抽象类不可以被创建对象。(实例化)。
4.只有通过子类继承抽象类并覆盖了抽象类中的所有抽象方法后,该子类才可以实例化,否则,该子类还是一个抽象类。
抽象类中的细节:
1.抽象类中是否有构造函数?有,用于给子类对象进行初始化。
2.抽象类中是否可以定义非抽象方法?
可以,抽象类和一般类没有太大区别,都是在描述事物,只不过抽象类在描述事物的时候,有些功能不具体,所以抽象类和一般类在定义上,都是需要定义属性和行为的,只不过,比一般类多了一个抽象函数,而且比一般类少了一个创建对象的部分。
3.抽象关键字abstract和哪些不可以共存?final,static,private。
4.抽象类中可不可以不定义抽象方法?可以,抽象方法的目的仅仅为了不让该类创建对象。
5.一般类和抽象类有什么异同?
相同之处:一般类和抽象类都是用于描述事物,里面都可以定义属性和行为,以及构造函数。
不同之处:一般类中不可以定义抽象函数,抽象类可以。一般类可以实例化抽象类不行。
一般类可以被继承,也可以不被继承,抽象类则一定要被继承,需要其子类覆盖所有的抽象方法子类才可以被实例化。
abstract方法:
分析事物的时候,发现了共性的内容,就出现向上抽取,会有这样的一种特殊的情况,就是功能声明相同,但功能主体不同
这时候也可以抽取,但是只抽取方法声明,不抽取方法主体,那么此方法就是一个抽象方法。
abstract class Person{ abstract void show(); abstract void inof(); void turn(){ } } class NewP extends Person{ @Override void show() { } @Override void inof() { } //不覆写的话会报错 } public class Demo { public static void main(String[] args) { //new Person();报错!因为抽象类不可以实例化 } }
抽象类的体现-模板模式:
解决的问题:当功能内部一部分实现时确定,一部分实现不确定,这时就可以把不确定的部分暴露出去,让子类去实现。
abstract class GetTime{ public l final void getTime(){ // 此功能如果不需要复写,可加 l final 限定 long start = System.currentTimeMillis(); code(); // 不确定的功能部分,提取出来,通过抽象方法实现 long end = System.currentTimeMillis(); System.out.println("毫秒是:"+(end-start)); } public abstract void code(); // 抽象不确定的功能,让子类复写实现 } class SubDemo extends GetTime{ public void code(){ // 子类复写功能方法 for(int y=0; y<1000; y++){ System.out.println("y"); } } }
- 接口
引入:抽象类是从多个类中抽象出来的模板,若要将这种抽象进行的更彻底,就得用到一种特殊的”抽象类“ ---》接口
接口只定义了类应该遵循的规范,却不关心这些类的内部数据和其方法内的实现细节。
接口只规定了这些类里必须提供的方法,从而分离了规范和实现,增强了系统的可扩展性和可维护行。
举例:
1.用关键字interface定义的。
2.接口中包含的成员,最常见的有全局常量,抽象方法,
注意:接口的成员都有固定的修饰符。
成员变量:public static final
成员方法:public abstract
interface Inter{ public static final int x = 3; //public static final 都可以省略 public abstract void show(); //public abstract 可以省略 }
3.接口中有抽象方法,说明接口不可以实例化,接口的子类必须实现接口的所有抽象方法后,该子类才可以实例化,否则,该子类还是抽象类。
4.类与类之间存在着继承关系,类与接口中间存在的是实现关系。
5.接口和类不一样的地方,就是,接口可以被多实现,这就是多继承改良的结果,java将多继承的机制通过多实现来体现。
6.一个类在继承另一个类的同时,还可以实现多个接口,所以接口的出现避免了单继承的局限性。还可以将类进行功能的拓展。
7.其实java中是有多继承的,接口与接口之间存在着继承的关系,接口是可以多继承的。
接口设计上的特点:
1.接口是对外提供的规则。
2.接口是功能的扩展
3.接口的出现降低了耦合性。
抽象类与接口:
抽象类:一般用于描述一个体系单元,将一组共性的内容进行抽取,可以在类中定义抽象内容让子类实现,也可以定义非抽象内容让子类直接使用,它里面都是体系的基本内容。
接口:一般用于定义对象的扩展功能,是在继承之外还需要这个对象具备的一些功能。
抽象类与接口的共性:都是不断向上抽取的结果。
抽象类和接口的区别:
1.抽象类只能被继承,而且只能单继承。接口需要被实现,而且可以多实现。
2.抽象类中可以定义非抽象方法,子类可以直接使用。
接口中都有抽象的方法,需要子类去实现。
3.抽象类使用的是 is a 的关系。
接口使用的是 like a 的关系。
4.抽象类的成员修饰符可以自定义。
接口中的成员修饰符是固定的,全部都是public。
- 内部类
类是用于描述事物的,而事物中如果还有具体的事物,而且这个内部的事物在访问着所属事物的内容,这时这个内部的事物也需要用类来描述,这个类就是内部类。
如果A类需要直接访问B类中的成员,而B类又需要建立A类的对象。这时,为了方便设计和访问,直接将A类定义在B类中就可以了,A类就成为内部类。内部类可以直接访问外部类中的成员。而外部类想要访问内部类,必须要建立内部类的对象。
特点:内部类可以直接访问外部类中的成员,外部类要访问内部类中的成员必须要创建对象。
1 class Outer 2 { 3 int num = 4; 4 //内部类。 5 class Inner 6 { 7 void method() 8 { 9 System.out.println("method run .."+Outer.this.num); 10 } 11 } 12 public void show() 13 { 14 Inner in = new Inner(); 15 in.method(); 16 } 17 } 18 19 20 class InnerClassDemo 21 { 22 public static void main(String[] args) 23 { 24 new Outer().show(); 25 } 26 }
当内部类定义在外部类的成员位置上,可以使用一些成员修饰符修饰private,static。
1.默认修饰符。
直接访问内部类的格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象;
Outer.Inner n in = = w new w Outer.new Inner();// 这种形式很少用
但是这种应用不多见,因为内部类之所以定义在内部就是为了封装,想要获取内部类的对象通常都通过外部类的方法获取,这样可以对内部类对象进行控制。
2.私有修饰符
通常内部类被封装,都会被私有化,因为封装性不让其他程序直接访问,
3.静态修饰符
如果内部类被静态修饰,相当于外部类,会出现访问局限性,只能访问外部类中的静态成员。
注意:如果内部类中定义了内部成员,那么该内部类必须死静态的。
内部类编译后的文件名为:外部类名$内部类名.java
为什么内部类可以直接访问外部类中的成员呢?
那是因为内部类都持有一个外部类的引用,这个引用是外部类名.this
内部类可以定义在外部类中的成员位置上,也可以定义在外部类的局部位置上。
当内部类被定义在局部位置上,只能访问局部中被final修饰的局部变量
匿名内部类
凡是匿名的都是简写的形式,定义匿名内部类必须要有前提。
前提:内部类需要继承或者实现一个外部的类或者接口,这时才能携程匿名内部类的形式。
匿名内部类其实就是一个匿名子类对象,这个对象用{}结尾内部定义了成员,
匿名内部类的格式:new 父类名&接口名(){定义子类成员或者覆盖父类方法}.方法。
匿名内部类的使用场景:
当函数的参数是接口类型的引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。
其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。