第五章 Java面向对象编程进阶
面向对象编程的三大特征:继承,封装,多态
5.1 继承extends
5.1.1 继承的实现
继承实现类的拓展,代码的重写,不用再从新发明新轮子
5.1.2 instanceof运算符
二元运算符,左边是对象右边是类,
当对象是右边类或子类创建的对象时返回true,否则返回false.
对象 instanceof 类
5.1.3 继承使用要点
1,父类也称为超类,基类,派生类。
2,Java中类只有单继承。接口则有多继承。
3, 子类继承父类,可以得到可以得到父类的全部属性和方法(除构造器),
但不见得可以总结访问(eg:父类私有的属性和方法)。
4,如果定义一个类时,没有调用extends,则他的父类是Java.lang.Object.
5.1.4 方法重写
子类通过重写父类的方法,可以用自身的行为替换父类的行为。
方法的从写是实现多态的必要条件。
方法的重写需要符合以下三个点:
1,"=="方法名,形参列表相同。
2,"<="返回值类型和声明异常类型,子类小于等于父类。
3,">="访问权限子类大于父类。
5.2 Object类
5.2.1 Object类的基本特性
Object类是所有类的父类,所有Java对象都拥有Object类的属性和方法。
如果在类声明中未使用extends关键字指明其父类,则默认继承Object类。
5.2.2 toString方法
Object类中定义有public String toString()方法,其返回值是String类型。
打印输出或者用字符串连接对象时,会自动调用该对象的toString()方法。
5.2.3 ==和equals方法
1,"=="代表双方是否相等,
基本类型表示值相等,引用类型表示地址相等,即同一个对象。
Object类中定义有 public boolean equals(Object obj)方法,
提供定义对象内容相等的逻辑。
Object的equals方法默认比较两个对象的hashcode,
是同一对象的引用时返回true,否则返回false.
也可以根据自己的要求重写equlse方法。
String,Date,包装类等,重写了Object的equals方法,
调用这些类的equals方法为:x.equlse(y)
当x和y引用的对象是同一类对象且属性内容相等时
(并不一定是相同对象)返回true否则返回false。
5.3 super关键字
super是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性。
使用super调用普通方法,语句没有位置限制,可以在子类中随便调用。
若是构造器的第一行代码没有显式带调用super(…)或this(…)
java都会默认调用父类的无参构造器。这里的super()可以省略。
继承树追溯
1,属性或方法查找顺序(eg:查找变量h)
1,在当前类中查找属性h.
2,一次上溯每个父类查找是否有h,直到Object为止。
3,如果没找到则出现编译器错误。
4,只要找到h这个变量就终止这个过程。
2,构造器调用顺序
1,构造器的第一句总是super(...),用来调用与父类对应的构造器。
流程为:
先向上追溯到Object,然后再依次向下执行类的初始化块和构造器
直到当前子类为止。
静态初始化调用顺序与构造器一样,不再重复。
5.4 封装encapsulation
5.4.1 封装的作用和含义
1,封装就是把对象的属性和操作结合为一个独立的整体,
尽可能的隐藏对象的内部细节。
2,程序设计要求"高内聚,低耦合" .
高类聚:内部数据操作细节在其内部完成,不允许外部干涉。
低耦合:指仅暴露必要的方法给外部使用,尽量方便被外部调用。
3,封装的优点:
1.提高代码的安全性
2,提高代码复用性。
3,高内聚:封装细节,便于修改内部代码,提高可维护性。
4,低耦合:简化外部调用,便于调用者使用,便于拓展和协作。
5.4.2 封装的实现---使用访问修饰符
1,Java四种访问控制符:private,default,protected,public.
使用他们尽量降低访问权限,提高安全性。
private:表示私有,只有自己的类可以使用。
default:表示没有修饰符修饰,只能访问同一个包的类。
protected:表示可被同一个包的类,及其他包中的子类访问。
public:表示可以被该项目中的所有包的所有类访问。
5.4.3 封装的使用细节
1,封装使用细节
类的属性的处理如下:
.一般使用private访问权限。
.提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,
以提供对属性的赋值操作与读取操作(boolean变量的get方法是is开头)。
.一些只用于本类的辅助性方法可以用private修饰,
希望其他类调用的方法 用public修饰。
5.5 多态poiymorphism
1,同一方法调用由于对象的不同,可能产生不同的行为
2,多态注意
1,多态是方法的多态,与属性无关
2,多态存在的三个条件:继承,方法重写,父类引用指向子类对象。
3,父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。
3,多态使用:
将父类的引用做方法的形参,实参可以是任意的子类对象,
通过不同的子类对象可以实现不同的行为方式。
4.多态优势:
提高代码的可拓展性,符合开闭原则
5,多态弊端:
无法调用子类特有功能
5.6 对象的转型(casting)
1,对象的转型分为向上和向下转型
向上转型:父类引用指向子类对象,属于自动类型转换。
向下转型:向上转型后的父类引用变量,只能调用它编译类型的方法,
不能调用他运行时类型的方法,这时就需要进行强制转换。
向下转型的过程中必须将引用变量转化成真实的子类类型,
否则会出类型转换异常(ClassCastException).
使用 instanceof 运算符进行判断来避免这种状况。
5.7 final关键字
1,final关键字作用:
1,修饰变量,被他修饰的变量不可改变。一旦被赋予初始值,就不能被重新赋值。
2,修饰方法,该方法不能被子类重写,但是可以被重载。
3,修饰类:修饰的类不能被继承
5.8 抽象方法和抽象类
1,抽象方法:
使用abstract修饰的方法,没有方法体,只有声明。
它定义的是一种规范,就是告诉子类必须要给抽象方法提供具体的实现。
2,抽象类:
包含抽象方法的类就是抽象类。抽象类通过abstract方法定义规范,
要求子类必须定义实现。通过抽象类可以严格限制子类的设计,
使子类之间更加通用。
抽象类的使用要点:
1.有抽象方法的类只能定义成抽象类
2.抽象类不能实例化,即不能用new来实例化抽象类。
3.抽象类可以包含属性,方法,构造器,但是构造器不能用new来实例化。
只能用来被子类调用。
4.抽象类只能用来被继承。
5。抽象方法必须被子类实现。
5.9 接口interface
接口就是规范,体现了"如果你是xxx就必须能XXX"的思想。
接口的本质就是契约,法律一样,制定好后大家都要遵守。
面向对象的精髓是对对象的抽象,最能体现这一点的就是接口。
5.9.1 接口的作用
1,普通内,抽象类,接口的区别:
普通类:具体实现。
抽象类:具体实现, 规范(抽象方法)。
接口:规范。
2,接口 是比 抽象类 还抽象的 抽象类,
它可以更加规范地对子类进行约束,全面、专业地实现了规范和具体实现的分离。
抽象类提供某些具体实现,但接口不提供任何实现,接口中的所有方法都是抽象方法。
接口是完全面向规范的,规定了一批类具有的公共方法规范。
从接口的实现者来看,接口定义了可以向外部提供的服务;
从接口的调用者来看,接口定义了实现者能提供的服务。
接口是两个模块之间通信的标准,是通信的规范。
接口和实现类只是实现规则的关系。
5.9.2 定义和使用接口
1,接口的声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2...]{
常量定义;
方法定义;
}
2,定义接口的详细说明:
1,访问修饰符:只能是public或默认设置。
2,接口名 :和类名采用相同的命名机制。
3,extends:接口可以多继承。
4,常量:接口中的属性只能是常量,总是以public static final修饰,不写也是。
5,方法:接口中的方法只能是public abstract,即使省略也是。
3,要点
1,子类通过implements来实现接口中的规范。
2,接口不能创建实例,但是可以用于声明引用变量类型。
3,一个类实现了接口,必须实现接口中的所有方法,并且这些方法只能是public的。
4,JDK1.7之前,接口中只能包含静态常量和抽象方法,不能有普通属性,构造器,普通方法。
5.JDK1.8后,接口中包含普通的静态方法。
5.9.3 接口的多继承
接口完全支持多继承。接口和类的继承类似,
子接口拓展某个父接口,将会获得父接口中所定义的一切。
5.9.4 面向接口编程
接口就是规范,是项目中最稳定的核心。
通过面向接口编程,而不是面向实现类编程,
可大大降低程序间的耦合性,提高整个系统的可拓展性和可维护性。
5.10 内部类
5.10.1 内部类概念
定义在一个类内部的类,目的是为了方便使用外部类的相关属性。
内部内可以使用public,default,protect,private以及static来修饰。
而外部顶级类只能使用public和default修饰。
内部内只是一个编译时的概念,一旦编译成功,就会称为完全不同的两个类。
内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。
1,内部类的作用;
.内部类提供了更好的封装,只能由外部内直接访问,
而不允许同一个包中的其他类直接访问。
.内部内可以直接访问外部类的私有属性,内部内被当成其外部内的成员,
但外部内不能访问内部内的属性。
.接口只是解决了多重继承的部分问题,而内部内使得多重继承的解决方案变得更加完整。
2,内部内的使用场合
1,由于内部内拥有根更好的封装性,并且可以很方便的访问外部类的属性,
所以,在只为外部内提供服务的情况下可以优先考虑使用内部内。
2,使用内部内间接实现多继承,每个内部内都能独立地继承一个类或者实现某些接口,
所以无论外部类是否已经继承了某个类或者实现了某些接口,都对内部内没有任何影响。
5.10.2 内部类的分类
Java中分为:
成员内部类(非静态内部类和静态内部类),匿名内部类,局部内部类
1,成员内部内
可以使用权限修饰符修饰,类文件为:外部类$内部内.class
1,非静态内部类:
.非静态内部类必须寄存在一个外部类对象里。非静态内部类对象单独属于外部类的某个对象。
.非静态内部类可以直接访问外部类的成员,但外部类不能直接访问非静态内部类的成员。
.非静态内部类不能有静态方法,静态属性和静态初始化块。
.外部内的静态方法,静态代码块不能访问非静态内部类,包括不能使用非静态内部内定义变量,创建实例。
成员变量访问要点:
内部类里的方法的局部变量:变量名。
内部类属性:this.变量名
外部属性:外部类名.this.变量名
内部类的访问要点:
在外部类中定义内部内:new Inner().
在外部类以外的地方使用非静态内部类:
Outer.Inner varname = new Outer().new Inner()
2,静态内部类
静态内部类的实列方法,不能直接访问外部类的实例方法。
静态内部类可以看作是外部类的一个静态成员变量,
外部内的方法中可以通过"静态内部内.名字"的方式访问静态内部类的成员变量,
通过new 静态内部类()访问静态内部类的实例。
2,匿名内部类
匿名内部内适合只需要使用一次的类,如键盘监听操作等。
语法格式为:
new 父类构造器(实参类列表)\实现接口(){
//匿名内部类类体。
}
匿名内部内没有访问修饰符,
匿名内部类没有构造器。
3,局部内部类
局部内部类定义在方法内部,作用域只限于本方法。
用于解决比较复杂的问题实际开发中使用少。
5.11 字符串String
5.11.1 String基础
1,String类又称为不可变字符。位于java.lang包中。
每个用双引号括起来的字符串都是String类的一个实例。
使用"+“符号连接字符串。
当”+"运算符两侧的操作数中有一个是字符串类型,
系统会自动将另一个操作数转换为字符串进行连接。
5.11.2 String类和常量池
1,常量池的分类:
全局字符串常量池(String Pool):
存放的是类加载完成后存放到String Pool中的,
在每个VM中只有一份,存放的是字符串常量的引用值(在堆中生成字符串对象实例)。
class文件常量池(Class Constant Pool):
在编译时每个class都有,在编译阶段它存放的是常量(文本字符串,final常量等)和符号引用。
运行时常量池(Runtime Constant Pool):
在类加载完成之后,将每个class常量池中的符号引用值转存到运行时常量池中。
即:每个class也都有一个运行时常量池,类在解析之后,将符号引用替换成直接引用,
与全局常量池中的引用保持一致。
5.11.3 阅读API文档
略
5.11.4 String类的常用方法
1,必须非常熟悉String类的使用方法
char charAt(int index);
返回字符串中第index个字符。
boolean equals(String other);
如果字符串与other相等,返回true,否则返回false。
boolean equalsIgnoresCase(Strign other);
同上,但忽略大小写。
int indexOf(String str);
返回从头开始查找第一个子字符串str在字符串中的索引位置。
如果未找到子字符串str,返回-1.
lastIndexOf();
返回从末尾开始查找第一个子字符串str在字符串中的索引位置。
如果未找到子字符串str,返回-1.
int length();
返回字符串长度;
String replace(char oldChar,char newChar);
返回一个新字符串,通过用newChar替换此字符串中出现的所有oldChar而生成的。
boolean startsWith(String prefix);
如果字符串以prefix开头则返回true。
boolean endWith(String prefix);
如果字符串以prefix结尾则返回true。
String substring(int beginIndex);
返回一个新字符串该串包含从原始字符串beginIndex到串尾。
String substring(int beginIndex,int endIndex);
返回一个新字符串该串包含从原始字符串beginIndex到串尾,
或endIndex-1的所有字符。
String toLowerCase();
返回一个新字符串,该串将原始字符串 中所有大写字母改成小写字母。
String toUpperCase();
返回一个新字符串,该串将原始字符串 中所有小写字母改成大写字母。
String trim();
返回一个新的字符串,该串删除了原始字符串头部和尾部的空格。
5.11.5 字符串相等的判断
equals方法用来检查两个字符串的内容是否相等。
如果字符串s和t内容相等,则s.equls(t)返回true,否则返回false。
要测试两个字符串除了大小写不同外是否相等,
需要使用equalsIsIgnoreCase()方法。
5.12 设计模式相关知识
5.12.1 开闭原则(Open-Closeed Principle)
指让设计的系统对拓展开放,对修改关闭。
对拓展开放指s
应对需求变化灵活,在增加新功能时不需要修改已有的代码,增加新代码即可。
对修改关闭指
核心部分经过精心设计后,不再因为需求而改变
5.12.2 相关设计模式
略S