今天的进度稍微有点紧张,周一计划的内容有些延后,今天又花了半天的时间完成。
一、继承:首先有反映一般事物特性的类,然后在此基础上反映出特殊事物的类。
•继承是从一般到特殊的关系。
•好处:提高代码复用性、开发效率。让类与类之间产生关系,多态的前提。
(1)子类与父类:
•父类的私有成员子类不能继承到;
•Java只可单继承,不可多继承;
•一个类有且只有一个直接父类;
(2)子类对象实例化过程:
先调用父类无参的构造方法目的是为了对继承自父类的成员做初始化操作。
(3)子类访问父类:
•子类不能直接访问父类的私有成员;但子类可调用父类中的非私有方法来间接访问父类的私有成员。
(4)覆写父类方法:
•子类拓展父类(子类是父类的一种特殊情况)
主要是以父类为基础,然后添加属于自己的字段和方法。
•子类需要覆写父类方法。
父类某个方法不适合子类本身特征行为时就要覆写父类中应当改变的方法。
(5)方法的覆写:
•当父类中某个方法不适合于子类时,子类出现父类一模一样的方法.
•判断技:子类方法前加上@Override能编译通过,表明是方法的覆写。
•调用被覆盖的父类方法:使用super.方法名(实参);
•覆写原则:
<一同>:方法签名必须相同;
<两小>:子类方法的返回值类型比父类方法的返回值类型更小或相等;
子类方法声明抛出的异常应比父类方法申明抛出的异常更小或相等;
<一大>:子类方法的访问权限应比父类方法更大或相等;
(6)super关键字:
•使用super调用父类的 方法 或 构造方法。
•子类调用父类的构造方法时:super必须放在第一句
•若子类构造方法中显式指定调用父类其他构造方法,就调用指定的父类构造方法,取消调用父类无参构造方法。
(7)this & super:
注:使用super()和this()在同一个构造方法中是不能同时显式出现。
二、多态:指同一个实体同时具有多种形式
•编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给变量的对象决定。
•如果编译时类型和运行时类型不同,就出现多态。
如:面馆吃面,说我要吃面,那老板给我牛肉面、鸡蛋面等都可以;即"面"有多种形态,即实体有多种形态;
Person p = new Person();
Student s = new Student();
Person p = new Student();
| |
编译时类型:声明的类型,把它看做是什么东西; 运行时类型:真正的类型,实际上指的是什么东西;
(1)实现多态的机制:
•父类的引用变量可指向子类的实例对象,而程序调用的方法在运行期才动态绑定,即引用变量所指向的真正实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
(2)多态的作用:
•把不同的子类对象都当作父类来看,可屏蔽不同子类对象间的差异,写通用的代码,做通用的编程,以适应需求的不断变化;
•只修改方法的实现,不必修改方法的声明;
(3)多态的分类:
•编译时多态:方法重载 •运行时多态:方法覆写
多态是用来屏蔽子类不同实现细节,例子是:
1 class Dog{ 2 3 public eat(){ 4 5 System.out.println("我吃的是通用狗粮"); 6 7 } 8 9 } 10 11 class Hashiqi extends Dog{ 12 13 public eat(){ 14 15 System.out.println("我吃的是哈士奇的专用狗粮"); 16 17 } 18 19 } 20 21 class BeijingDog extends Dog{ 22 23 public eat(){ 24 25 System.out.println("我吃的是北京犬的专用狗粮"); 26 27 } 28 29 } 30 31 public class Zoo{ 32 33 //喂养 34 35 public static void feed(Dog d){ 36 37 d.eat(); 38 39 } 40 41 public static void main(String[] args){ 42 43 Dog d1=new Hasiqi(); 44 45 feed(d1); 46 47 Dog d2=new BeijingDog(); 48 49 feed(d2); 50 51 } 52 53 }
/**
可以看到多态的好处就是,我统一了喂的方法。如果没有多态,我们只能在Zoo类这样写:
public static void feed(Dog d);
public static void feed(BeijingDog d);
public static void feed(Hasiqi d);
*/
注意,多态的使用,一般都会出现三方,第一方是父类,第二方是子类,第三方是调用多态的方法。看完这个例子之后,通过画图,来描述调用的关系。
(4)引用变量类型转换:
- 向上转型(子类→父类):(自动完成)
父类名称 父类对象 = 子类实例 ;
- 向下转型(父类→子类):(强制完成)
子类名称 子类对象 = (子类名称)父类实例 ;
对象名 instanceof 类
判断指定的变量名此时引用的真正类型是不是当前给出的类或子类;
注意: 对象的 类型 和 类 必须有继承关系
转型,也可以直接使用这个例子,什么时候会出现大--->小,就是在子类中有自己特定的方法的时候,需要强转。
比如:
1 class Hasiqi extends Dog{ 2 3 public eat(){ 4 5 System.out.println("我吃的是哈士奇的专用狗粮"); 6 } 7 8 public laxueqiao(){//拉雪橇 9 10 System.out.println("我能拉雪橇"); 11 } 12 } 13 class BeijingDog extends Dog{ 14 15 public eat(){ 16 System.out.println("我吃的是北京犬的专用狗粮"); 17 } 18 19 public tiaoxi(){ 20 System.out.println("我能被调戏"); 21 } 22 } 23 24 .....main..... 25 26 public static void feed(Dog d){ 27 28 d.eat(); 29 30 if(d instanceof Hasiqi){ 31 32 Hasiqi temp=(Hasiqi)d; 33 34 temp.laxueqiao(); 35 36 }else if(d instanceof BeijingDog){ 37 38 BeijingDog temp=(BeijingDog)d; 39 40 temp.tiaoxi(); 41 } 42 } 43 44 这个例子能展示在真实应用当中的多态的使用方式。
(5)多态时方法的调用:
•当一个引用类型的变量若声明为父类的类型,但实际上引用的是子类的对象(多态情况):
•此时该变量不能再访问子类中自己特有的字段和方法;
•若子类覆写了父类的方法,那么此时通过变量访问到的方法,实际上是子类的方法;
三、包装类说明:
除了Integer和Character定义的名称和对应的基本类型差异大,其他六种都是将首字母大写就可以了;除了Character和Boolean是都是Object直接子类外,另外6个是Number类的子类;且这8个类都是final修饰的(不可被继承)。
(1)基本数据类型和包装类相互转换:
•把基本数据类型→包装类:
通过对应包装类的构造方法实现;除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象。
•包装类→基本数据类型:
包装类的实例方法xxxValue(); // xxx表示包装类对应的基本数据类型
(2)自动装箱&自动拆箱:
自动装箱:可把一个基本类型变量直接赋给对应的包装类对象或则Object对象
自动拆箱:允许把 包装类对象直接赋给对应的基本数据类型
Integer i = 3;//装箱
int i2 = i;//拆箱
Object flag = new Boolean(false);
if(flag instanceof Boolean){
Boolean b = (Boolean)flag;
boolean b2 = b;
}
(3)基本类型和String之间的转换:
String → 基本类型:
除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量;
基本类型 → String:
String 类有静态方法valueOf(),用于将基本类型的变量转换成String类型。
(4)Object类:
•所有类的公共父类,一旦一个类没有显示地继承一个类则其直接父类一定是Object类且一切数据类型都可用Object接收。
class OOXX extends Object{}等价于class ooXX {}
•常见方法
public boolean equals(Object obj):对象比较
public int hashCode():取得该对象的Hash码
public String toString():对象描述
•建议所有类都覆写此方法
•直接打印输出对象时,会调用该对象的toString()方法。
•打印对象的时候,实际调用的对象实际指向的类的自我描述;
•全限定类名[email protected]+十六进制的hashCode值,等价于全限定类名[email protected]+IntegertoHexString(该对象.hashCode)
四、Singleton模式(单态模式):
目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例。
好比一个国家就只有一个皇帝(XXX),此时每个人叫的“皇帝”都是指叫的XXX本人;
常见单例模式类型:
- 饿汉式单例
- 懒汉式单例
l 懒汉模式,它的特点是运行时获得对象的速度比较慢,但加载类的时候比较快。它在整个应用的生命周期只有一部分时间在占用资源。
l 饿汉模式,它的特点是加载类的时候比较慢,但运行时获得对象的速度比较快。它从加载到应用结束会一直占用资源。
l 这两种模式对于初始化较快,占用资源少的轻量级对象来说,没有多大的性能差异,选择懒汉式还是饿汉式都没有问题。但是对于初始化慢,占用资源多的重 量级对象来说,就会有比较明显的差别了。所以,对重量级对象应用饿汉模式,类加载时速度慢,但运行时速度快;懒汉模式则与之相反,类加载时速度快,但运行 时第一次获得对象的速度慢。
l 从用户体验的角度来说,我们应该首选饿汉模式。我们愿意等待某个程序花较长的时间初始化,却不喜欢在程序运行时等待太久,给人一种反应迟钝的感觉,所以对于有重量级对象参与的单例模式,我们推荐使用饿汉模式。
Singleton(饿汉模式)
1 Singleton(饿汉模式) 2 3 class Singleton 4 5 { 6 7 ///在内部准备好一个对象 8 9 private static Singleton instance = new Singleton(); 10 11 public static Singleton getInstance(){ 12 13 return instance; 14 15 } 16 17 private Singleton(){} 18 19 public void show(){ 20 21 System.out.println("Singleton"); 22 23 } 24 25 }
Singleton(懒汉模式)
1 Singleton(懒汉模式) 2 3 class Singleton{ 4 5 private static Singleton instance = null; 6 7 public static Singleton getInstance(){// 将instance传递到外部去 8 9 if(instance == null){ 10 11 instance = new Singleton(); 12 13 } 14 15 return instance; 16 17 } 18 19 private Singleton(){} 20 21 } 22 23 //更完美的写法,避免多线程创建多个实例 ----->双重检查锁定 24 25 public static Singleton2 getInstance() { 26 27 if(instance==null) 28 29 { 30 31 synchronized(Singleton2.class) 32 33 { 34 35 if(instance==null) 36 37 instance = new Singleton2(); 38 39 } 40 41 } 42 43 return instance ; 44 45 }
enum实现单例模式
l 使用枚举来实现单例模式的好处是这样非常简洁,并且无偿地提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。
1 public enum Singleton { 2 3 INSTANCE;//唯一实例 4 5 public static Singleton getInstance(){ 6 7 return INSTANCE; 8 9 } 10 11 public void show(){ 12 13 System.out.println("使用enum实现单例模式"); 14 15 } 16 17 }
final关键字
① final可以修饰类,方法,变量。
② final修饰类不可以被继承,但是可以继承其他类。
③ final修饰的方法不可以被覆盖,但可以覆盖父类方法。
④ final修饰的变量称为常量,这些变量只能赋值一次。
⑤ 内部类在局部时,只可以访问被final修饰的局部变量。
final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变;
通常规范中:常量名称所有字母大写,若有多个单词组成,单词间使用下划线连接。
public static final修饰的常量称为全局常量;
抽象类的引入:abstract 关键字
可以定义被abstract修饰的抽象方法
抽象方法只有返回类型和方法签名(方法名 + 参数列表),没有方法体。
抽象类可以含有普通方法
抽象类不能创建实例对象(不能new)
需要子类覆盖掉所有的抽象方法后才可以创建子类对象,否则子类也必须作为抽象类
流的四个基本父类
InputStream,OutputStream,Reader,Writer
abstract方法
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是功能声明相同,但功能主体不同。
那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
abstract [非private访问修饰符] 返回值类型 方法名称(参数列表);
抽象方法要存放在抽象类中。
抽象方法也可以存在于接口中