- import sun.NET.www.content.text.Generic;
- import java.lang.reflect.Array;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
- public class Test {
- public static void main(String[] args) {
- // ClassTypeCapture.test();
- // InstantiateGenericType.test();
- CreatorGeneric.test();
- }
- }
- /*
- 15.8 擦除的补偿
- -- 标记下, 这个地方乱七八糟, 我有点混乱
- 因为擦除的问题, 我们有时候必须通过引入类型标签来对擦除进行补偿. 这意味
- 着你需要显式地传递你的类型的 Class 对象, 以便你可以在类型表达式中使用它.
- 在前面的例子中对 instanceof 的尝试最终失败了, 因为其类型信息已经被擦除了.
- 如果引入类型便签, 就可以转而使用动态的 isInstance().(前面的失败完全是
- 因为非要将一个具体类型标签符给一个没有指明的类型标签)
- */
- class Building { }
- class House extends Building { }
- class ClassTypeCapture<T>{
- Class<T> kind;
- public ClassTypeCapture(Class<T> kind){
- this.kind=kind;
- }
- public boolean f(Object arg) {
- /*
- 这个地方应该涉及到了 Class 对象储存信息方面的问题
- */
- return kind.isInstance(arg);
- }
- public static void test() {
- // ClassTypeCapture<Building> ctt1 = new ClassTypeCapture<>(Building.class);
- // System.out.println("ctt1.f(new Building()):"+ctt1.f(new Building()));
- // System.out.println("ctt1.f(new House()):"+ctt1.f(new House()));
- //
- // System.out.println();
- ClassTypeCapture<House> ctt2 = new ClassTypeCapture<>(House.class);
- System.out.println("ctt2.f(new Building()):"+ctt2.f(new Building()));
- System.out.println("ctt2.f(new House()):"+ctt2.f(new House()));
- }
- }
- /*
- 我把上一个案例的代码, 和解读贴在这儿, 帮助我理解一下这个问题:
- 即使 kind 被存储为 Class<T>, 擦除也就意味着它实际将被存储为 Class, 没有任何参数.
- 因此当你在使用它时, 例如在创建数组时, Array.newInstance() 实际上并未拥有 kind
- 所蕴含的类型信息, 因此这不会产生具体的结果, 所以必须转型, 这将产生一条令你无法满
- 意的警告.
- */
- class ArrayMaker<T>{
- // 运行时实际保存的是 Class<Object>
- private Class<T> kind;
- public ArrayMaker(Class<T> kind) {
- // 这个地方在运行时, 把一个 Class<T > 赋给了 Class<Object>
- this.kind=kind;
- }
- @SuppressWarnings("unckecked")
- T[] create(int size) {
- return (T[]) Array.newInstance(kind,size);
- }
- public static void test() {
- ArrayMaker<String> s = new ArrayMaker<>(String.class);
- String[] stringArray = s.create(9);
- // System.out.println(Arrays.toString(stringArray));
- }
- }
- /*
- 15.8.1 创建类型实例
- 需求:
- 解决在在泛型类中不能用 T t 创建对象的方案. Java 中可以传递一个工厂对象, 并使用它来
- 创建新的实例. 最便利的工厂对象就是 Class 对象, 因此如果使用类型标签, 那么你可以使用
- newInstance() 来创建这个类型的新对象.
- */
- class ClassAsFactory<T>{
- T x;
- T y;
- Class<T> k;
- public ClassAsFactory(Class<T> kind) {
- try{
- x = kind.newInstance(); // 这个地方没有将 kind 对象存给任何被擦除了的对象哦
- System.out.println("x:"+x.getClass().getName());
- /*
- 很奇怪, 我这儿并有发生前文描述的任何问题?
- */
- k=kind;
- y = k.newInstance();
- System.out.println("y:"+y.getClass().getName());
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InstantiationException e) {
- e.printStackTrace();
- }
- }
- }
- class Employee { }
- // 这个方案由于问题不是在编译期报出来, 故不推荐
- class InstantiateGenericType {
- static void test() {
- new ClassAsFactory<Employee>(Employee.class);
- System.out.println("ClassAsFactory<Employee> succeeded");
- //
- // ClassAsFactory<Integer> f1 =
- // new ClassAsFactory<>(Integer.class);
- }
- }
- //Sun 建议使用的显式工厂
- interface Factory<T>{
- T create();
- }
- class Foo2<T>{
- private T x;
- public <F extends Factory<T>> Foo2(F factory){
- x = factory.create();
- }
- }
- class IntegerFactory implements Factory<Integer>{
- @Override
- public Integer create() {
- return new Integer(0);
- }
- }
- /*
- 这个为什么会报错啊!!!
- class Widget{
- // 嵌套类实现一个工厂, 但是报错了, 说是循环实现
- static class Factory implements Factory<Widget>{
- public Widget create() {
- return new Widget();
- }
- }
- }
- */
- class FactoryConstraint{
- static void test() {
- new Foo2<Integer>(new IntegerFactory());
- // new Foo2<Widget>(new Widget.Factory());
- }
- }
- /*
- 最后一种在泛型类中实例参数对象的方法: 使用模板方法设计模式.
- */
- abstract class GenericWithCreate<T>{
- final T element;
- GenericWithCreate(){
- element=create();
- }
- abstract T create();
- }
- class X{}
- class Creator extends GenericWithCreate<X>{
- @Override
- X create() {
- return new X();
- }
- void f(){
- System.out.println(element.getClass().getSimpleName());
- }
- }
- class CreatorGeneric{
- static void test() {
- Creator c = new Creator();
- c.f();
- }
- }
- /*
- 最后做一个自己的实验, 验证一下现在真的不可以在泛型类中创建参数化对象么?
- */
- class A<T>{
- T t;
- A(){
- //t = new T(); 果然不可以
- }
- }
- /*
- 15.8.2 泛型数组
- -- 这部分东西, 我暂时不研究了, 很枯燥, 而且感觉价值并不是太高
- 解决不能创建泛型数组的方案: 在任何想要创建泛型数组的地方都使用 ArrayList
- */
- class ListOfGenerics<T>{
- private List<T> array = new ArrayList<>();
- public void add(T item){array.add(item);}
- public T get(int index){return array.get(index);}
- }
- /*
- 有时, 你仍旧希望创建泛型类型的数组 (例如, ArrayList 内部使用的是数组). 有趣的是
- 你可以按照编译器喜欢的方式来定义一个引用, 例如:
- */
- class H<T> {}
- class ArrayOfH{
- static H<Integer>[] gia;
- }
- /*
- 编译器接受这个程序, 而不会产生任何警告. 但是, 永远都不能创建这个确切类型的数组 (包括
- 参数类型), 因此这有点令人困惑. 既然所有数组无论它们持有的类型如何, 都具有相同的结构
- (每个数组槽位的尺寸和数组的布局), 那么看起来你应该能够创建一个 Object 数组, 并将其
- 装换成所希望的数组类型. 事实上这可以编译, 但是不能运行, 它将产生 ClassCaseException
- */
- class ArrayOfGeneric{
- static final int SIZE = 100;
- static H<Integer>[] gia;
- @SuppressWarnings("unchecked")
- static void test() {
- gia = (H<Integer>[])new H[SIZE];
- }
- }
- /*
- 成功创建泛型数组的唯一方式就是, 创建一个被擦除类型的新数组, 然后对其转型
- */
来源: http://www.bubuko.com/infodetail-2991568.html