文章目录
类型信息Class
只保存定义类、接口、方法时泛型的占位符,而不会保存实例化时的确切类型信息
Class a<T, M, N>{}
String str1 = Arrays.toString( a.class.getTypeParameters() );
String str2 = Arrays.toString( (new a<Integer, String, Float>()).getClass().geetTypeParameters() );
System.out.println( str1 );
System.out.print( str2 ); // l两者输出的信息完全一样,并没有保存已经确切定义时的信息
RTTI(Run-Time Type Information) :在运行时,识别一个对象的确切类型(多态)
- 类加载器: 加载( 创建Class对象 ) → 链接( 为静态域分配存储空间 ) → 初始化( 初始化静态域 )
- Class对象:保存类的信息
- 每个类都有Class对象 —— 每当编译一个新类,就会产生Class对象
- 产生该Class对象 → 使用JVM的类加载器的子系统
- 一旦“对应类”的Class对象载入内存,它就可以创建“对应类”的对象
- 静态常量: 编译器常量(确定值得大小),无需对类初始化
Class方法:
- forName( 完全限定名 ) —— 完全限定名:包名+类名 注:可能会抛出异常,所以需捕捉异常 —会初始化类
- 类名.class —— 生成一个该类名的Class对象,无须捕捉异常 ——不会初始化类
同一种类型的对象(类名完全相同,不能继承),他们公用一套Class信息对想
Auto auto1 = new Auto();
Auto auto2 = new Auto();
if( auto1.getClass() == auto2.getClass ) { // output: equal
System.out.println("equal"); // 故可得知同种类的Class对象相同(共用)
}
- getName() = getCanonicalName(): 返回包名+类名
getSimpleName(): 返回类名
- 类型比较: 对象 instanceof 类名
Class实例 . isInstance( 对象 )
Class实例 . isAssignableFrom( Class实例 )
- getConstructors()、getConstructor(参数类型信息数组) —— 得到的是有public修饰的构造函数
getDeclaredConstructors()、getDeclaredConstructor(参数类型信息数组) —— 得到的是所有定义构造函数即使是private
- Class实例.cast( Object a): 返回一个“无检查”的"强制转型" (T)a
- Class实例.getClasses(): 返回一个该类内定义的公有类信息
- Array.newInstance(数组类型信息, 维数数组): —— 返回一个数组对象
- getComponentType() : —— 返回 数组的组件信息的Class 非数组则返回null
- getEnclosingClass() : —— 返回该内部类的上一层类的信息
class A {
public static B {
public class C {
}
}
}
// 测试
A.B b = new A.B();
b.getClass().getEnclosingClass() // 返回 A的class信息
A.B.C c = b.new C();
c.getClass().getEnclosingClass() // 返回 B的class信息
泛型的Class引用:Class
- 加入 泛型<T> 仅仅只是为在编译期间进行检查,而不必在运行期自己发现。
- 可以指定固定类型的Class引用 注意:Class T指定了什么就是什么,即使是父类也不能用其作为引用 —— 除非在 <>显示的写明继承
Class<Integer> integer = int.class
// integer = Number.class 这是错误的,即使Number是Integer的父类,因为class<Integer> 与 class<Number> 无继承关系。
Class<?> random = double.class // " ? " 代表什么类型都可以
random = integer;
Class<? extends Number> number= int.class; // 只要继承与Number类的都可以。
number = double.class;
Class<Son> son = Son.class;
// cCass<Father> father = son.getSuperclass(); 虽然son的继承父类是Father但也不能明写,只能用下面那种 因为源码该函数返回的是 class<? super T>
Class<? super Son> son = son.getSuperclass();
强制转换
Class<Father> father = Father.class;
Son son = new son();
Father fa = father.cast(son); // 强制转换 转换成Class<T> T的类型
Father fa = (Father)son //前面 三步 等价于 一步
Class得到的反射 - 暴露一切
- 运用Class类型信息得到的反射 —— 可以使整个类所有暴露出来,即使是私有,依然可以被调用,俗称“ 后门 "
- 访问private\protected时,注意设置 (Method/Field实例).setAccessible( true ); → 用来抑制java语言访问权限
- 反射依然不能修改final变量 —— 反射set不会报错
- javap -p -private class文件:该语句能显示所有在该类明面写的方法
interface Father {
public void one();
String str2 = "str2";
}
class Son extends Father {
private String str1 = "str1";
public void one() {}
private void Two() {}
private final Integer number = 6; //虽然反射能set final变量并且鬠报错,但终究没有修改成功。
}
public static void main(String[] args) {
Class classSon = Son.class;
Method[] methods1 = classSon.getMethods(); //返回的是public方法,即使是及成成的也行
Method[] methods2 = classSon.getDeclaredMethods(); //返回的是在该类"明面"写的所有权限的方法,故不包括没在该类重写的继承方法。
Field[] fields1 = classSon.getFields(); // 跟上面类似
Field[] fields2 = classSon.getDeclaredFields()
}
Array —— 可用于生成数组、查值、修改数组值、数组长度
class Test {
public static void main(String[] args) {
Integer[] numbers = { 1, 2, 3, 4, 5 };
int[] numbers2 = {1, 2, 3, 4, 5 };
int length = Array.getLength( numbers ); // 得到数组的长度
Object integer = Array.get( numbers, 0 ); // 得到非基本类型数组的指定位置元素
int integer2 = Array.getInt( numbers2, 0 ); // 得到基本类型数组的指定位置元素
Array.set( numbers, 0, 10); // 修改非基本类型数组的指定位置元素
Array.setInt( numbers2, 0, 10); // 修改基本类型数组的指定位置元素
// 创建多维数组
Integer[][] num1 = Array.newInstance( Integer[].class.getComponentType(), {1,2} );
Integer[] num2= Array.newInstance( Integer[].class.getComponentType(), {10} );
// 创建一维数组
integer[] num3 = Array.newInstance( Integer.class.getComponentType(), 10 );
注册工厂模式 —— (工厂方法变体)
- 创建一个泛型为输出对象类的工厂接口,方法为 返回类型为输出对象(即泛型)的方法。
- 输出对象类创建一个继承该工厂接口的静态工厂类
Package library;
interface Factory<T> { // 具体的颜色类内部静态工厂 实现这个接口 这里的T是具体颜色
T create(); // 生成具体颜色。
}
class Color {
static List< Factory<? extends Color> > colorFactory = new List< Factory<? extends Color> >(); //保存一系列颜色的生成器,即具体颜色工厂器
static {
colorFactory.add(new White.Factory()); //初始化“具体颜色工厂器”的列表
}
}
class White extends Color {
public static class Factory implements library.Factory<White> { //实现工厂接口,接口需注意写包名,要不然系统优先用最近的类名。即内部类Factory,以导致出错。
public White create() {
return new White();
}
}
代理模式
厂家是“委托者”,微商代理是“代理者”
“代理者”筛选了客户,且隐藏了“委托类”的实现
静态代理
interface Sell {
void sell();
}
class Vendor implements Sell { //厂家
public void sell() { System.out.println( "I am Vendor.sell()" ); }
}
class Proxy implements Sell { //代理者,聚合,且进一步封装接口方法,筛选用户群体
Sell proxy = new Vendor();
public void sell() {
System.out.print("Proxy: ");
proxy.sell();
}
动态代理 —— 运用上面的接口Sell、委托类Vendor
Proxy.newProxyInstance(代理类的加载器[ClassLoader],需要代理类的接口的Class数组Class[],方法的调用处理器[InvocationHandler] )
class Handler implements InvocationHandler{ //引用处理器,代替 ”代理者”的筛选作用
Object proxied = new Vendor();
public Object invoke(Object Proxy, Method method, Object[] args) {
System.out.print("Proxied: ");
return method.invoke(proxied,args);
}
}
public static void main(String[] args) {
ClassLoader cl = Sell.class.getClassLoader():
Class[] jk = {Sell.class};
Handler hd = new Handler();
Sell proxy = (Sell) Proxy.getProxyInstance(cl, jk, hd); //生成一个动态代理,(类加载器、需要帅选的方法接口,引用处理器)
proxy.sell(); //只要运行jk参数里面的方法,都会调用引用处理器里面的invoke函数
}
方法类Method
-
获取Method实例
- Class实例.getMethod(方法名,参数Class数组) 得到指定类中的方法
- Class实例.getMethods() 得到指定类的所有方法
-
调用Method实例的方法
- Method实例.invoke(类对象,实参数组)
class Test {
public void cout() { System.out.println("I am cout()"); }
public static void main(String[] args) throws Exception{ //Class类中的getMethod会抛出异常
Class test = Test.class;
Method methodCout = test.getMethod("cout", null); //获取Method实例——且获取的为Test类中的cout方法
methodCout.invoke(new Test(), null); //调用指定类对象中的cout()
}
单例模式
一个类只能构建一个对象的模式
public class Dog { //懒汉模式
publc static Dog dog = null;
private Dog() {
name = "DogMei";
}
public static Dog getDog() {
if(dog == null) {
dog = new Dog();
}
return dog;
}
}
public static void main(String[] args) { //另一个类的主函数Main
Dog dog1 = new Dog(); //错误,不能生成,因为构造函数私有化了
Dog dog2 = Dog.getDog(); //能运行
}
空对象
更靠近数据,因为对象表示的是问题空间内的实体
空对象逻辑变体: 模拟对象、桩
在原类内部定义静态的空对象类
interface Null {}
class Person {
String name;
String sex;
public final static NullPerson NULLPERSON = new NullPerson(); //空对象,到时定义Person对象为空时,直接赋值该静态空对象 Person people = Person.NULLPERSON
Person(String name, String sex) {
this.name = name;
this.sex = sex;
}
public String toString() {
return name+ ", " + sex;
}
public static class NullPerson extends Person implements Null { //空类继承父类实现Null接口,该内部列必须是static,因为空对象要设置静态。需提前加载。
private NullPerson(){ //单例,该类只能有一个实例对象
super("none","none");
}
}
}
同一父类多种子类定义空对象,用代理设置空对象
interface Null{}
interface Person{ //父类
String getWorkType();
String getName();
}
class Painter implements Person { //可定义多种子类,如果做空对象的话,需每个子类都要写,麻烦,冗余代码。
String name = "小明";
public String getName() { return name; }
public String getWorkType() { return this.class.getSimpleName; }
}
class NullPersonProxyHandler implements InvocationHandler { //用动态代理进行多种子类空对象生成
String type;
Object prooxied = new NullPerson();
NullPersonProxyHandler(Class<? extends Person> type) { //Proxy的参数,参数是子类的Class说明
type = type.getSimpleName() + "NullPerson";
}
class NullPerson implements Null,Person {
public String getName() { return type; }
public String getWorkType() {return type; }
}
public Object invoke(Object proxy, Method method, Object[] args) {
return method.invoke(np, args); //覆盖子类的同名方法
}
}
public static void main(String[] args) {
Person person = (Person)Proxy.newProxyInstance( Person.class.getClassLoader(), new Class[]{ Person.class, Null.Person } , new NullPersonProxyHandler(Cat.class) );
泛型
泛型细节
适用于许多许多的类型,目的:希望类或方法能够具备最广泛的表达能力 —— 只用一套代码表达更多的类型 —— 泛型参数可以是异常类
在创建参数化类型的实例时,编译器保证负责转型操作,并且保证类型的正确性
初始化时,告诉编译器使用的类型—— 静态检查,单纯是静态检查,依然能突破用其他类型进行调用( 强制转换 )
class Human implements Comparable<Human> {
String name;
Human( String name ) { this.name = name; }
public int compareTo( Human human ) { //只要被调用,直接输出int型结果,不会发生异常
int thisCode = name.hashCode();
int humanCode = human.name.hashCode();
if ( thisCode > humanCode ) return 1;
else if ( thidCode = humanCode ) return 0;
else return -1;
}
}
//测试
Object o = new Object();
Human hum = new Human("lrc");
hum.compareTo( (Individual)o ) // 这里依然能调用成功,而且最后异常 这是不希望发生的,所以依然需要增加类型检测
List list : 能够持有任何Object类型的原生List —— 无编译器期类型检查
List<?> list: 具有某种特定类型的非原生List
List list: 运行前能检测类型的特定类型非原生List
List list1 = new ArrayList<Integer>();
List<?> list2 = new ArrayList<Integer>();
List<Integer> list3 = new ArrayList<Integer>();
list1.add("fadfsdf") //依然能增加,因为系统直接把形参当作Object类型
失败:list2.add(5) // 泛型变量,依然没显示的指明 整形5是符合标准的,即使改成 <?extends Integer>也不行,需改成超类型匹配 < ? super Number>,不过这也导致其能加Number字型对象
list3.add(5) //运行成功
定义泛型边界时 class A< T entends 类 & 接口 & 接口> —— 只能边界限定一个Class类,但能限定多个interface
- 在初始化泛型时,只能初始化你完完整整定义的边界的类型 —— 初始化比定义时边界范围不小于
class A{}
interface B{}
interface D{}
class E extends A implements B,D {}
class AGenerator<T extends A & B & D> {}
public static void main(String[] args) {
AGenerator<E> ag = new AGenerator<E> (); // 这个是正确的,初始化的泛型参数完完全全符合定义时的边界,范围不小于定义时的范围,
AGenerator<A> ag = new AGenerator<E> () //这个错误的,初始化的边界缩小。
泛型接口 在实现时最好指定 泛型类型 —— 基本类型无法作为类型参数
class Holder<T> {
private T a;
Holder(T a) { this.a = a }
}
泛型初始化: Holder<Integer> holder = new Holder<Integer>(5) // 故T = Integer,编译器进行 T 转化成 Integer
类内部是泛型组合时,当调用泛型组合的方法时,需明确定义边界 —— 只有当你的泛型跨多个类工作时,泛型才显得有所作为
class a {
public void cout() { System.out.println( " I am a " );
}
class Test<T extends a> { // 组合类 对象a是类Test的组合,当调用对象a的成员函数时泛型需要明确泛型的边界
T a;
Test(T a) { this.a = a; }
public void cout() { a.cout() } //因为定义了<T extends a >这个边界 , 所以可以调用该方法
}
泛型类型检查(静态检查): 只会在编译期间检查,而在运行期间就不在检查,而选择擦除所有泛型 —— 即最后只是保存为向上转型的Object类型、并且 T 也不会存在
- 克服运行时删除T参数类型,只能在初始化时有个字段保存T的类型信息
- 然后可以用 Class实例.isInstance( 对象 ) 既可以在 运行时而不仅仅是编译期间判断 输入对象是否符合要求
List<T> 只会在编译期间检查类型,检查完成后擦除泛型变为: List
public <T> void cout( T a ) {
if ( a istanceof T ){} //直接报错,侧面的说明T在运行时已经被完完全全的擦出
}
元组(tuple)
运用泛型将 一组多种不同类型对象 直接存储变为 一个对象(类似组合)—— 数据传送对象,信使
通过继承机制可实现更长的元组
class Tuple<A,B,C> { // 三元组
public final A one;
public final B two; //定义为public、final这种书写更加的简洁,而不必设置为私有,又要设置get()方法进行获取
public final C three;
Tuple(A one, B two, C three) {
this.one = one;
this.two = two;
this.three = three;
}
}
自定义简易堆栈
class LinkedStack<T> {
private class Node { //结点 一个保存内容、一个保存下一个结点的引用
T item;
Node next;
Node() { item = null; next = null; }
Node(T item, Node next) { this.item = item; this.next = next; }
void isEmpty() { return item == null && next == null; }
}
private Node top = new Node(); //末端哨兵,pop先弹出这个结点
public void push(T item) { top = new Node(item, top); } //压栈,创建新结点
public T pop() { //出栈
T result = null;
if( top.isEmpty() != true ) {
result = top.item;
top = next;
}
return result;
}
public boolean isEmpty() { return top.isEmpty() ) //判断该top结点是不是最后一个
}
适配器模型
- 一个类的接口变换成客户端所期待的另一种接口 —— 电脑电源插头是三相的,插座(客户端)没有三相的插口,只有两相,这是需要一个转换器三相变两相使得适配插座
- 在不知类源码的情况下,导致不能重写该类增加功能,只能用现有的类通过继承实现该有的接口
class Fibonaci { //假设这个源码的控制权不在你这里-不能重写这个类增加功能
int count = 0;
Integer next() {
return fib(count++);
}
private Integer fib(int a) {
if( a < 2 ) return 1;
else return fib(a-2) + fib(a-1);
}
}
class FibonacciIterator extends Fibonacci implements Iterable { //适配器,加功能,通过继承实现接口
int size = 0;
FIbonacciIterator(int count) { this.size = count; }
public Iterator iterator<Integer>() {
return new Iterator<Integer>() {
int number = size
public boolean hasNext() {
if(number > 0 )
reutrn true;
else return false;
}
public Integer next() {
number--
return FibonacciIterator.this.next();
}
};
}
泛型方法
泛型方法可独立于泛型类,即定义泛型方法可不用定义泛型类
能使用泛型方法取代整个类的泛型化就尽量用泛型方法 —— 可使代码更加的简单清晰
泛型方法对于泛型类的差别是:不必显示声明泛型参数,而通过实参 编译器会判断泛型的参数类型
泛型静态方法调用返回值 用来做实参需指明泛型参数类型
泛型参数不能重载相同的泛型行参 —— 运行时,泛型参数类型消失,导致方法签名一样
编译期检查是在数据类型(参数的检查)、而<>泛型里面必须一一对应
下面的成员函数两两互相冲突,导致错误,因为函数调用是在运行时,类型已经抹除,故方法签名都一样重复
public Father<A, B> {
public void one( List<A> list ) {}
public void one( List<B> list ) {}
public void one( List< String > list) {}
public void one( List< Integer > list) {}
}
class Create {
public static <T> List list() {
return new ArrayList<T>();
}
public static void test(ArrayList<Integer> a) {}
}
public static void main(String[] args) {
ArrayList<Integer> listInteger = Create.list() //这个是可以的,有参数类型判断
//Create.test( Create.list() ) 这个错误,需显示的泛型参数类型T
Create.test( Create.<Integer>list() ) //这个正确
class GenericMethod {
public <T> List<T> makeList(T... args) {
List<T> list = new ArrayList<T>();
for( T t : args) { list.add(t); }
return list;
}
}
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
System.out.println( gm.makeList(1,2,3,4,5,6) //调用泛型方法时无需显示声明泛型参数
}
泛型数组
- 实质泛型数组最终还只是定义了 Object[],并没有定义指定的泛型数组
- 创建泛型数组唯一方式: 创建被擦出泛型的数组 → 进行转型
- 创建数组最好的方式是,构造函数传进去的是初始化后泛型的类型信息
用 Array.newInstance(类型信息, 长度) —— 这就创建了指定泛型的数组
Class Father<T> {
T[] arrays;
Father(int length) {
arrays = (T[])new Object[length]; // 这里的强制转换一点都没作用,运行时还是赋值了 Object[] 数组
}
Father(Class<T> type, int length) {
arrays = (T[]) Array.newinstance(type, length); // 这里创建的就是指定初始化后的指定类型数组
}
public T[] array() { return arrays; }
}
public static void main(String[] args) {
Father<Integer>[] fathers = ( Father<Integer>[] )new Father[]() //不可缺少转型,否则报错,实质运行时强制转型没什么作用。
Father<Integer> father = new Father<Integer>();
Integer[] number = father.array(); //编译期并无显示错误,运行时直接抛出 “ClassCastException异常”再次说明泛型只是在编译器检测而已,运行期完全不起作用
Object[] number = father.array(); //这个就正确,因为终究还只是 Object[]
}
边界
- 子类的泛型约束可直接嫁接到父类 —— 继承
class Father<T> {}
class Son<T extends Number> extends Father<T> {}
- <>内的泛型多继承 可调用其继承类、接口方法
class A { void acout() {} }
interface B { void bcout(); }
class Son<T extends A & B> {
T item; // 此时 item 就有权限调用 类A、接口B 的方法
public void test() {
item.acout();
item.bcout();
}
- 单纯的<> 可加“水果"
class A {}
class B extends A {}
class Test<T> {
T item;
Test(T item) { this.item = item; }
public void set(T item) { this.item = item; }
}
//主函数
public static void main(String[] args) {
Test<A> test = new Test<A>(new A());
test.set(new B()); // 并没有错误
}
- 上界通配符<? extends 类> —— 单纯只是为了赋值向上转型,实质并没有像数组一样真正起作用的是指向的引用 → 无协变性 —— 泛型初始化赋值的是?—— 更宽的实参范围
- <? extends T>作用: 一个能初始化水果的盘子,但不能加水果,因为系统识别不了你是什么水果盘子
class Fruit{}
class Apple extends Fruit;
class Banana extends Fruit;
class Plate<T> {
T fruit;
public void set(T fruit) { this.fruit = fruit; }
public T get() { return fruit; }
}
Plate<? extends Fruit> fruitPlate = new Plate<Apple>(); //系统能识别你是水果盘子,但不能识别你是什么具体类型的水果盘子
fruitPlate.set(new Apple()) // 发生错误,不能识别具体类型T
- 泛型容器变量 代码意义上的向上转型 则 丢失 添加对象的能力 (Object对象也不行) —— add(T e) 其参数是泛型,故不可以
- 只要赋值后的泛型变量,调用其泛型变量对象的方法只要形参不是 泛型T 就可以完调用
class Father {}
class Son extends Father {}
Father[] a = new Son[6];
a[0] = new Son();
a[1] = new Father(); //运行错误,在编译前并无错误,因为a变量本来就是Father类型 → 说明数组有协变性
//错误: List<Father> list = new ArrayList<Son>() 泛型的标准是一是一,二就是二,爸爸不认的儿子就不是儿子。
List<? extends Father> list = new ArrayList<Son>() //泛型变量中爸爸直接认儿子
//错误 ;list.add(new Son() ) 一旦泛型变量 “代码意义上的强制转型” 则丢失传递对象的能力,即使Object也不行 —— 形参为泛型
-
超类型通配符(逆变、下界通配符) — < ? super 类/泛型T > —— 泛型初始化赋值的是T —— 传递确定的参数
- 使这个泛型能持有某种具体的类型,不再会跟普通的泛型会在运行中系统自动清除
- 能放具体水果,且是水果的基类的盘子
引用上面上界通配符的类
Plate<? super Fruit> plate = new Plate<Fruit>();
Plate<? super Fruit> plate = new Plate<Object>();
plate.set(new Apple()); //能放水果
List<? super Numder> = new ArrayList<Number>();
list.add(43); // 运行成功,泛型直接持有了具体的类型信息
List<? extends Number> = new ArrayList<Number>();
list.add(43) // 直接编译期间给出错误
public static <T> cout( List<? super T>, T item ) {} //调用 cout( new ArrayList<Number>, 43 ); 没问题
-
无界通配符 ? —— 捕获
- 泛型内泛型,注意放变量跟初始化一样 —— 嵌套初始化泛型需一模一样
class Father<T>{}
List< Father<?> > list = new ArrayList< Father<?> >() //无界匹配符不能填写确定的符号
错误: List< Father<?> > list = new ArrayList< Father<String> >() //编译器错误
list.add( Father<String> ); //只有在只能一个泛型时才能改成确切的类型
2. 一旦被赋值无界通配符,这个符合就仿佛捕获了确切的参数类型 (编译期)
List<?> a = new ArrayList<Integer>();
public static <T> void test( List<T> list) {}
public static <T> void test( List<T> list, T item ) {}
test(a) //运行成功
test(a, new Integer(5) ) //不能运行,知道捕获有实际类型,但又不能得到是实际类型的什么。
参数化接口
- 不能同时继承同一个泛型接口的的两个变体,因为运行时泛型类型并无作用
总之继承的两个泛型变体需要 泛型参数相同
interface One<T>{}
class Two implements One<String> {}
class Three implements One {}
class Four extends Two implements One< Integer> {} //编译错误,由于类型被擦出并不能识别重写以及继承的类,故错误
class Four extends Two implements One< String>{} // 可以这样编写
class Five extends Three implements One{} // 可以这样编写
自限定
- 新类直接继承泛型类,不过这个继承的泛型的参数类型为该新类 —— 提供了模板
class Temple<T> {
T item;
Temple() { item = null; }
public T get() { return item; }
public void set(T item) { this.item = item; }
}
class Son extends Temple<Son> {} //继承了Temple所有方法,不过其边界是新类本身
public static void main(String[] args) {
Son son1 = new Son();
Son son2 = new Son();
son1.set(son2); //son1 保存了son2对象
Son son = son1.get(); //得到son1里面的son2对象
- 保证继承的类型参数与正在被定义的类相同 —— 限定了输入输出T类型需要是Father的子类
class Father<T extends Father<T> > {} //一旦初始化,限定了T必须继承Father<T>的前提
class Son extends Father<Son>{} //Father充当模板,并且限定Son必须继承Father的前提
class Son2 extends Father<Son> //这个没错,因为Son的相关继承属性没有被打破
class Son3{}
class Son4 extends Father<Son3>{} //这条语句表达的意思是 Son3 extends Father<Son3> , 然而实际Son3并没有继承Father ,故冲突, 编译期错误
混型 —— java不允许(实质是多重继承)
C++混型能拥有所混入的所有方法
template<class T> class Father : public T {}
template<class T> class Son : public T{}
class Basic{}
Father<template<Basic>> mix //mixb变量能用 Father、Son、Basic 的方法
替代性的实现混型可用接口 —— 用代理实现
- 静态代理
interface Name() { String getName(); }
class NameImp implements Name {
String name = "a";
String getName() { return name; }
}
interface Basic {
void set(int value);
int getId();
}
class BasicImp implements Basic {
int id;
public void set(int value) { this.id = value); }
public int getId { return id; }
}
class Mix extends BasicImp implements Name { //混型,代理,多重继承
NameImp ni = new NameImp();
public String getName() {
return nI.getName();
}
}
动态代理 —— 更加贴近混型
由于动态代理的要求:必须要某个接口的实现类实例来调用
class TwoTuple<A, B> {
A first;
B second;
TwoTuple(A first, B second) {
this.first = first;
this.second = second;
}
}
class MixinProxy implements InvocationHandler {
Map<Method, Object> proxyMethods;
//传一个二元对象数组( 二元分别为 接口实例,接口类型信息 )
MixinProxy(TwoTuple<Object, Class<?>>... args) {
for( TwoTuple<Object, Class<?>> tt : args) {
for(Method method : tt.second.getMethods() ) {
String methodName = method.getName();
if( proxyMethod.containsKey(methodName) == false )
proxyMethod.put( methodName, tt.first );
}
}
}
//调用方法,从proxyMethods中得到 方法对象
public Object invoke( Object proxy, Method method, Object[] args ) {
mathodName = method.getName();
Object object = proxyMethods.get( methodName );
return method.invoke( object, args);
}
//返回一个代理对象
public static Object newInstance( TwoTuple... args) {
Class<?>[] interfaces = new Class<?>[args.length];
for( int i = 0 ; i < interfaces.length; i++) {
interfaces[i] = args[i].second;
}
ClassLoader cl = args[0].first.getClass().getClassLoader();
Object proxy = Proxy.newInstance( cl, interfaces, new MixinProxy( args) ) ;
return proxy;
}
}
潜在类型机制 —— 无需继承,调用不属于该目前类的方法
支持这机制的是C++(静态)、Python(动态) ,java不支持
该实例对象只要有这个方法,就能调用,不在乎当前的类型缩小方法接口,没有这个方法,则运行报错
折中用反射实现该机制 :
{
//需要调用的方法,假设
public void speak();
}
public static void invoke (Object object) {
Class<?> type = object.getClass();
try {
try {
Method speakMethod = type.getMethod("speak");
speakMethod.invoke(object);
}catch(NoSuchMethodException e) {
println(type.getSimpleName() + "no speak method");
}
}catch( Exception e) {
throw new RuntimeException(e);
}
}
- 容器以及有容器的类可公用一个方法,只写一个方法
- 可静态检查,可多种自定义容器使用
- 适配器模式
// 用这个接口来泛化 Apply.fill方法
interface Addable<T> {
public void add(T item) ;
}
//定义通用方法
class Apply {
public static <T> void fill(Addable<T> addable, Class<? extends T> type, int size){
try {
for(int i = 0; i<size; i++) {
addable.add(type.newInstance());
}
}catch(Exception e) {
throw new RuntimeException(e);
}
}
}
//静态代理Collection中的add方法
class AddableCollectionAdapter<T> implements Addable<T> {
Collection<T> collection;
AddableCollectionAdapter(Collection<T> collection) {
this.collection = collection;
}
public void add(T item) {
collection.add(item);
}
}
//适配上面静态代理的类,用Adapter 静态方法生成该类
class Adapter {
public static <T> Addable<T> collectionAdapter(Collection<T> collection) {
return new AddableCollectionAdapter<T>(collection);
}
}
//单纯只实现了Iterable的自定义组合容器
class SimpleList<T> implements Iterable<T> {
ArrayList<T> list = new ArrayList<T>();
public Iterator<T> iterator() {
return list.iterator();
}
public String toString() {
return list.toString();
}
}
//适配SimpleList 需要实现Addable接口
class AddableSimpleList<T> extends SimpleList<T> implements
Addable<T> {
public void add(T item) {
list.add(item);
}
}
适配器、策略模式结合的 —— 接近混型
方法参数为策略接口,传入不同的策略类运行同一方法不同效果
紧耦合
函数对象,仿函数:可以传递出去,拥有多个调用之间持久化的状态
//主类方法需要用到的泛型类
interface Combiner<T> {
public T combine(T x, T y);
}
//适配器
public IntegerAdder implements Combiner<Integer> {
public Integer combine(Integer x, Integer y) {
return x+y;
}
}
public class Test {
public static <T> T jiehe(Iterable<T> seq, Combiner<T> combiner) {
Iterator iterator = seq.iterator();
if( iterator.hasNext() ) {
T result = iterator.next();
while( iterator.hasNext() ) {
result = combiner.combine(result, iterator.next() );
}
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1,2,3,4,5,6);
System.out.println(Test.jiehe( list, new IntegerAdder() ) ); //output: 21
}
)