Java - 泛型的理解2

http://www.jianshu.com/p/7e3e2b898143
这是上次写的泛型,当时其实还是一知半解。
今天再做个小总结,但也还是一知半解吧。
今天老师上课,讲了很多泛型的东西。
generics

第一个东西,叫做 type parameter
其中有部分,我到现在还是不懂。

<T>void print(Collection<T> c) {
  for (T x : c)
      print("elem " + x);

}

至于这个,void 左边的 <T>到底是干什么的,老师给我解释了两遍还是不能很理解。他的意思就是,这是一种规矩。

public class Demo<T>{
     public T a;
     public Demo(T k) {
            a = k;
      }

      <T>void change(T k) {
                a = k;
       }
}

这样是有编译错误的。
如果把void 左边<T>去掉就对了。
所以我当时做的结果是,如果这个函数是要修改自己的元素,那么不能加<T>,如果是要修改外面传进来的元素,那么就加<T>,不会报错。
比如,

<T> void change(T k) {
     k = null;
}

但是老师说不是。他说我第一个为什么会错呢?只要把<T>换个名字不和T重复就行了。我换了,果然就对了。为什么呢?下次office hour得去问下。

下面进入一个正题。

ArrayList<Object> b = new ArrayList<Object>();
b.add(5);
b.add("abc");

char a = (char) b.get(0);
编译时不报错,运行时报错。
generics是编译时可见,运行时擦除的。
所以编译的时候,编译器知道,b.get(0)返回的是一个Object类型,语法上可以被强制转换成其他类型。于是就通过了。运行时,擦除了<T>的信息。于是,系统尝试着将Object类型强制转换成char。但是我们都知道,这个object对象的内存块,本质是Integer。
所以,只能被强制转换成Integer,不能被强制转换成char。
于是报错了。

char a = b.get(0);
编译时报错。
因为编译时是知道generics的<T>的。所以一匹配,一边是char,一边是object,不匹配,直接编译错误,static error

Integer a = b.get(0);
编译错误,不能自动cast。这是超类转子类,必须cast

Integer a = (Integer) b.get(0);
编译通过,运行通过。

改一下,
ArrayList<Integer> b = new ArrayList<Integer>();
b.add(5);
Object a = b.get(0);
Object c = (Object) b.get(0);
都是对的。
子类转超类,不需要cast,会自己转。

然后是上篇文章讨论的问题。
LinkedList<ArrayList<Integer>>[] a = new LinkedList<ArrayList<Integer>>[100];
这个在编译时是无法通过的。
因为数组是运行时才会开始着手考虑元素类型的问题。但是这个时候<T>已经被擦除了,返回的内存可能不安全。于是Java提前在编译时就把这个错误找了出来,提前规避这个风险。
但其实,我测试过,
int[] a = new int[5];
a[0] = "abc";
a[100] = 5;
第一个是编译错误,第二个是运行错误。
也就是说,在编译时,数组是可以知道,他的元素的种类的。
我还过另外一个说法。这里为什么会编译错误,因为,Java的作者当时忘记写这块了。。。于是乎。。。
不管怎么样,记得不能这么用吧。具体改造方法那篇文章里有。
其中,强制转换是这样的,

LinkedList<ArrayList<Integer>>[] c = (LinkedList<ArrayList<Integer>>[]) new LinkedList[100];

或者,采用ArrayList来做。

List<Object> a = new ArrayList<String>();

为什么是不对的?

List<String> stringList = new ArrayList<String>();
List<Object> objectList = stringList ;
objectList .add(new Integer(5));
String temp = stringList.get(0);

按道理,stringList.get(0); 应该返回一个String
但是这里返回的是一个Integer
为了增加安全性,Java同样决定在编译时,就提前规避这种风险,不让这种东西可以被写出来,可以通过编译,可以运行。
但是可以这么改。

List<Object> objectList = (List<Object>) (List<?>) stringList;

先转换成,一种不知道什么类型的类型。在转换成object。
但是这是有警告的,而且如果你之前不知道所存的元素本质是什么,这么用是很危险的。
所以,<>所存放的东西,他们必须,完全一致。

List<List<Integer>> = new ArrayList<ArrayList<Integer>>(); // ERROR!
List<List<Integer>> = new ArrayList<List<Integer>>(); // RIGHT!

然后老师提到了这么一个运算符 <?>
LinkedList<?> means LinkedList<T> for some T
但是,之后这个链表返回的元素,只能用Object来接收,因为他自己都不知道,他返回的是什么东西。
Object o = llist.first();
还可以这么用,
LinkedList<? extends Puzzle> means LinkedList<T> for some T extends <Puzzle>

使用泛型的限制。

不能使用primitive types as T
比如, Collection<int> 错误!!!

cannot create a T like:
new T();
or
T[] a = new T[n];
因为在运行时会把编译时知道的T信息擦除掉,所以不知道T到底是什么,不知道怎么申请什么样的内存。

cannot inspect T at run time
like
instance of T
instance of Collection<String>
因为编译时,不知道<T> 是String

最后说下,Comparator
这块只是一直没怎么学习过。
Comparator是一个interface
里面有两个方法,

public class A implements Comparator<T> {
        public int compare(T a, T b) {....}     
}

因为传入的T不知道类型,这是复杂版本,不知道怎么处理。
如果传入的类知道类型,复杂的情况,就是不能简单地用java系统方法,compareTo,就得自己写一个compareTo去判断大小。
简单地话,传进来的类自己实现了Comparable 接口,于是直接调用compareTo() 方法就行了。
如:

public class A implements Comparator<Integer> {

public int compare(Integer a, Integer b) {
            if (a.compareTo(b) < 0)
                    return -1;
            else if (a.compareTo(b) > 0)
                    return 1;
            else
                    return 0;
    }   
}

然后在一个新类中,

public class B {

      public void sort(int[] a, Comparator<Integer> q) {
        for (int i = 1; i < a.length; i++) {
            for (int j = i; j >= 1; j--) {
                if (q.compare(a[j - 1], a[j]) > 0) {
                    int temp = a[j];
                    a[j] = a[j - 1];
                    a[j - 1] = temp;                }
            }
        }
    }

      public static void main(String[] args) {
            int[] array = {3, 4, 2, 6,19, 1};
            B test = new B(); 
            test.sort(array, new A());
      }

}

就可以实现排序了。
Comparator 比较的是两个数的大小,他的角度是,客观的看到一串数,是旁观者。
public int compare(T a, T b) {....}
Comparable 比较的是自己和另外一个数的大小,他的角度是,当局者,他只看到另外一个数。
public int compareTo(T other) {....}
他们都是接口。主要就是本身的意义不同。

然后还有个问题。
Arrays.sort(array, new A());
是报错的,那么Arrays.sort()这个方法该如何使用comparator呢?我得去问问老师。
就先写到

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,567评论 18 399
  • 背景 一年多以前我在知乎上答了有关LeetCode的问题, 分享了一些自己做题目的经验。 张土汪:刷leetcod...
    土汪阅读 12,719评论 0 33
  • (一)Java部分 1、列举出JAVA中6个比较常用的包【天威诚信面试题】 【参考答案】 java.lang;ja...
    独云阅读 7,066评论 0 62
  • 小编费力收集:给你想要的面试集合 1.C++或Java中的异常处理机制的简单原理和应用。 当JAVA程序违反了JA...
    八爷君阅读 4,568评论 1 114
  • 豆瓣博主 企业好好做相关的技术帖或者行业风险剖析和揭露 知乎大V 看知乎工具 微博 三大段子手 项目立案 预算和目...
    史成玉阅读 212评论 0 0