文章目录
1.多态
多态(动态绑定): 可理解为子类向上转型转成基类并调用基类方法,实质调用的是父类被子类覆盖的方法。 —— private方法不会被重载、重写,故不会动态绑定、static方法、字段也无动态绑定
动态绑定是与对象相关联而不是类——static是绑定类的。
构造函数也能动态绑定,不过这会招致难以意料得错误,如父类构造,用了未被初始化的子类字段值
class father {
int a = 0;
void draw()
{
System.out.println("a= " + a);
};
father() {
draw();
}
}
class son extends father {
int b = 1;
void draw {
System.out.println("b= " + b);
}
入口函数 son s = new son();
//最后结果是:b = 0;
//因为在初始化父类时,son类的对象s并还没有创建,更无从谈起初始化的 b=1
私有方法不会动态绑定:
class One extends Test{
private void cout() {
println( "One Cout()" );
}
}
class Test {
private void cout() {
println( "Test Cout()" );
}
public static void main(String[] args) {
Test test = new One();
test.cout(); // output: Test Cout() 私有方法没有动态绑定
}
}
2.接口 - 解耦
抽象类abstract
只要类方法有关键词abstract修饰-不准写具体的实现,必须用同样的关键词abstract修饰类
继承的子类必须重写父类所修饰的那些方法,否则子类必须抽象修饰
接口interface
- 接口类似抽象类,不过完完全全是只提供接口的“抽象类”,接口的使用,具体实现需像继承一样 用关键词 implements
- 接口方法是 public权限、字段是final、static权限 则说明了接口中的字段是域了且能直接使用无须继承(像类中的静态变量一样使用)
- 接口中定义了 static修饰的方法 必须要有函数主体
- 如果创建不带任何方法定义及成员变量的基类 → 优先选择这个基类定义为接口,而不是抽象类(能够定义方法)
- 接口与接口之间能继承 方法签名同优先级:接口具体的方法 > 继承类的方法
- 接口与接口之间能嵌套,定义方法时需指定内嵌的接口才行
- 接口可以像类一样,可作为参数,可向上转型等 ——记住是实例方法,需创建对象调用
- 同一个类可继承多个接口 —— 可覆盖更加具体的返回类型同名方法
- 同名同返回的参数类型,不可以覆盖父类有关继承关系的方法
class Father {
public void cout(Father father) {
println("Father.cout()"};
}
}
class Son extends Father { //有两个方法,而不是一个方法,并没有覆盖cout()方法
public void cout() {
println("Son.cout()");
}
}
Father father = new Father();
Son son = new Son();
son.cout(father); //输出:Father.cout()
son.cout(son); //输出:Son.cout()
class Father{}
class Son extends Father{}
interface One { Father get(); }
interface Two extends One { Son get(); } //覆盖了One中的get()方法
interface Instrument {
interface teacher {
void name();
}
int a = 5;
void play();
}
class wind implements Instrument, Instrument.teacher { //内嵌接口需明确的指定
public void play() {
System.out.println(" wind's voice is wuwuwu " );
}
public void name() {
System.out.println("我是内嵌teacher接口的方法");
}
}
public class zhulei {
static void cout(Instrument a) { //接口类似类一样,也能让子类向上转型
a.play();
}
public static void main(String[] args) {
System.out.println(Instrument.a); //输出的结果是5,说明接口字段(域)能直接使用无需继承后在使用——静态变量
wind w = new wind();
cout(w); //因为该函数是静态函数,故调用该函数不用实例化对象。
//输出 : wind's voice is wuwuwu
}
}
工厂模式
运用接口的工厂方法:好处多个不同的对象能用同一函数调用(如各种棋子的移动、各种自行车的移动)
interface Wager {
void cast();
}
interface WagerFactory {
Wager getWager();
}
class Coin implements Wager {
public void cast() {
Random a = new Random(50);
int result = a.nextInt(2);
switch(result) {
case 0:print("coin'face is down"); break;
case 1:print("coin'face is on");
}
}
}
class CoinFactory implements WagerFactory {
public Wager getWager() {
return new Coin(); //向上转型
}
}
public class Factories {
public static void cast(WagerFactory a) { //多个不同对象同用一个方法,向上转型
Wager c = a.getWager();
c.cast();
}
public static void main(String[] args) {
CoinFactory cf = new CoinFactory();
cast(cf);
}
}
装饰模式
- 四元素: 抽象组件(基础)、具体组件、抽象装饰类(包含具体组件)、具体装饰类(包含组件)
interface House{ void style(); } //抽象组件
class ChineseStyle implements House { public void style() { println("Chinese's House"); } //具体组件
class EuropeanStyle implements House { public void style() { println("European's Hosue"); } //具体组件
class HouseDecorator implements House { //抽象装饰类
Hosue house;
HosueDecorator( House hosue) [ this.house = house; }
public void style() { house.style(); }
}
class RedDecorator implements HosueDecorator { //具体装饰类
RedDecorator(Hosue hosue) { super(house); }
public void style() {
println("red" + house.style() );
}
}
3.内部类
- 外部类内的静态方法用到内部类的实例化,大前提是外部类已经有实例化(外部类对象)且引用名需提到外部类类名 外类名.内部类名 引用名 = 外类实例.内类实例
public class Outer {
public class Inner1{}
class Inner2{}
static class Inner3{}
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner1 Inner1 = new Outer.Inner1(); //与下面两者效果一样,跟内部静态一样
Outer.Inner1 Inner1 = outer.new Inner1();
Outer.Inner2 inner2 = outer.new Inner2(); //普通内部类实例
Outer.Inner3 inner3 = new Outer.Inner3(); //静态内部类实例
}
}
-
this:前面指向的类名是谁则指向谁 例如:类名.this → 指向的是当前该类名对象的引用
-
内部类虽然定义了private →意思是你不能自行生成创建该对象(new),不过其对外开放的public方法依然能调用。
-
局部内部类(方法内定义类)
-
匿名内部类(直接在成员方法返回一个对象)
interface father {
void cout();
}
public class Test {
public static father generator() {
return new father() { //直接返回一个class、interface父类对象(自动向上转型,意味的匿名内部类在外部类使用时仅仅只能用到父类的方法,而匿名内部类的的其他方法只能辅助父类的方法使用,仅仅是这样
private int i = 6;
public void cout() {
System.out.println(i);
};
}
}
- 工厂设计另一种方法: 外类中设置一个静态的公有变量用来引用外列对象生成器
interface factory { a generator(); }
public class a {
public stataic factory ga = new factory() { //到时直接用 静态变量ga 生成 a对象
public a generator() { return new a(); }
};
- 嵌套类: 用关键词“ static "修饰的内部类,无外围类的引用
- 应用程序框架: 被设计用于解决某类特定问题的一个类或一组类
控制框架: 特殊的应用程序框架,解决响应事件的需求事件驱动系统: 用来响应事件的系统
解耦-虽然能隐藏子类的方法
interface Father {
void a() {}
}
class Son implements Father {
private void cout() {}
public void a() {}
public void b() {}
}
public static void main(String[] args) {
Father father = new Son();
//father.b(); 不可调用,向上转型已经减少方法访问接口。
Method[] methods = father.class.getDeclaredMethods() //用反射能进行调用被封闭的方法接口。甚至是private都能调用
Method m = father.class.getDeclaredMethod("cout");
m.setAccessible(true); //调用前需设置这个为 true
m.invoke(father); //私有调用成功
4.持有对象 — 容器
- java容器类库用:快速报错:探查是否有多个进程同时修改容器 → 不使用复杂的算法事后检查
ConcurrentHashMap、CopyOnWriteArrayList/Set → 可避免" 共同修改异常“这个异常
- 容器类的泛型,即使明确了泛型的类型,得到的Class类型信息还是一样
- 表明Class 只是保存定义数组时所写的泛型标识符,而不是自己在实例化类时的类型信息
Class a = new ArrayList<Integer>();
Class b = new ArrayList<String>();
if( a == b ) System.out.println("true"); //输出:true Class运行时类型信息一样
容器
容器中基本上实现或者继承了 Collection接口,故都可以向上转型为Collection
JCF(Java collections framwork) 虚线:类的实现(implements)、接口的继承 实线:类的继承(extends)
Hashtable、Vector、Stack 这三个容器是老版本的,现在的目的:为了支持老程序,所以在新的程序最好别使用
- ArrayList容器 保存的是父类对象的引用即 Object
因为底层容器是数组:随机访问很快( 与长度无关 )、插入,迭代器( 慢 )
如果指定 泛型(类型,可多个) 就不能添加该类型之外的对象 ArrayLIst<类型/泛型>
- Map(接口)的实现类: HashMap (最快的查找)、TreeMap (升序(键) 保存键值——始终保持键的排序状态、耗资源)- 基于红黑树、LinkedHashMap (插入顺序保存、保留HashMap的查找速度)- 基于链表
Map中的内部接口是在抽象类 AbstractMap实现
散列码(Hash):对象的int值 → 对象的某些信息进行转换而成(相对唯一)
TreeMap:唯一带有 subMap(参数) 方法的 Map类
LinkedHashMap:构造器参数true → 遍历则为LRU最近最少使用,否则为元素插入顺序遍历
-
List(接口)的实现类:
- Arrays.asList() - 固定长度: 保存的单纯的是指针并非引用,故能set,修改并不能作用到原列表——无法取数据类型的列表(无法泛型化) 注意:这里返回的ArrayList是Arrays里面的内部类ArrayList,该内部类并没有重写add(),remove()等方法 —— 这个类单纯只是个包装器,实质类内对象依然是该数组引用
- list(接口).subList(): 就是保存的原列表中的视图,一改两者都会改变(像视图跟基本表的关系) 返回的是ArrayList中的内部类SubList,该内部类重写了add, remove, set, 宛如一个可操作的列表 —— 依然只是ArrayList内的数组,不过他有add方法,该方法是每增加一次就创建的一个新的数组,重新赋值数组变量引用
- LinkedList:执行插入、删除的速度比ArrayList快,随机访问较慢(链表)- 实现了栈(Stack)、队列(Queue)、双端队列(Deque) 的接口方法 → 底层存储数据是:双向链表
-
Set(接口)的实现类
- 具有Collection完全一样的接口 (继承了Collection、Iterator接口)
- TreeSet( 保持比较排序顺序 - 元素必须实现Comparable接口 )
- LinkedHashSet( 保持插入顺序 - 链表、元素定义hasCoide() )
- HashSet(最快的查询速度 - 元素必须定义hasCode() —— 任何Object都有定义这个方法,无需担心)
接口SortedSet —— TreeSet需实现的接口
方法:- comparator(): 返回该Set使用的 Comparator比较器
- first() / last(): 返回首/尾元素
- subSet(元素1,元素2): 返回 [元素1,元素2) 范围内的Set视图
- headSet(元素) / tailSet(元素): 返回小于该元素 或者 大于等于该元素 的Set视图
- BitSet
- 存储“开关”信息
- 比本地数组稍微慢 - 最小容量64位
- Queen(接口)的实现类 ——并发编程重要、可靠的将对象从一个区域传输到另一个区域
- 不能把对象添加
- 实现了LinkedList接口
迭代器:统一各种容器的处理方式的轻量级对象 [接口](设计模式)
- next(): 局部类实现Iterator接口 父类“指针”整型 cursor = i + 1、返回局部成员 i
- ListIterator实现类: 只能用于List的实现类、双向移动-“双指针” 、指定迭代器一开始指向的位置
继承容器类或实现接口时 记得加泛型 —— 否则只能传Object的参数
Iterable接口
- 正因为容器类都实现了这个接口所以能用foreach遍历
所以说明要想要自己设定的容器类能实现遍历,则需新增 实现Iterable接口 – 其实就是写一个iterator()的方法
class squene implements Iterable<T> { //这个类的实例能直接 foreach
Integer[] number = { 1,2,3,4,5,6};
public Iterator<Integer> iterator() { //实现Iterable接口的方法
return new iterator<Integer>() {
count = 0;
public boolean hasNext() { return count < number.length; }
public next() { return number[count++]; }
public remove() {}
};
}
}
class Array2<T>{
T[] arrays;
Array2(T[] a) {
this.arrays = a;
}
}
ListIterator - 允许正向反向遍历器接口
源码 - ArrayList 内部类 ListItr
cursor:下一个元素的序号、lastRet:当前已经输出的元素序号
应用实例
Integer[] a = {1, 2, 3, 4, 5}
List<Integer> list = new ArrayList<Integer>( Arrays.asList(a) );
ListIterator<Integer> it = list.listIterator( list.size() ); //起始点为容器长度
while( it.hasPrevious() ) { // 判断是否序号 = 0;
System.out.print( it.previous() + " " );
} //output: 5,4,3,2,1