mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签
所有文章 友链 关于我

mhcoderwl

自顶向下探索世界,自底向上改变世界 -----WL

  • 主页
  • 标签

Java学习笔记6

2017-12-28

day7

1.泛型

与c++泛型的第一个区别是,java泛型的参数T不能为基本数据类型,如果是int编译器自动推导成Integer。

泛型第一个应用就是可以创造生成器,工厂模式的一个应用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
public interface Generator<T>{
T next();//一般一个生成器就定义一个方法用来获取对象。
package wangliang;
import java.util.*;
interface Generator<T>{//生成器,定义一个方法next()用来获得对象。
public T next();
}
class Coffee{
}
class Latte extends Coffee{
}
class Mocha extends Coffee{
}
public class CoffeeGenerator
implements Generator<Coffee>,Iterable<Coffee>{
private int size=0;
List<Class> types=Arrays.asList(Latte.class,Mocha.class);
private static Random rand=new Random(47);
CoffeeGenerator(int sz){
this.size=sz;
}
public Coffee next(){
try{
return (Coffee)types.get(rand.nextInt(types.size())).newInstance();
}catch (Exception e) {
throw new RuntimeException(e);
// TODO: handle exception
}
}
public Iterator<Coffee> iterator(){
return new Iterator<Coffee>(){
private int count=CoffeeGenerator.this.size;
public Coffee next(){
count--;
return CoffeeGenerator.this.next();
}
public boolean hasNext(){
return count>0;
}
public void remove(){
}
};
}
public static void main(String[] args){
}
}

对于模板方法的定义与c++不同,要在返回值的后面加上模板参数:

1
2
public <T> void f(T x){}

2.Iterator与Iterable

java.lang.Iterable是一个接口interface,一般用来实现这个接口可用于iterator()方法。这个接口也是我们自己设计类时常实现的接口,我们不直接实现Iterator,而是实现Iterable。

为什么这样做呢?

因为Iterator接口的核心方法next()或者hasNext() 是依赖于迭代器的当前迭代位置的。 如果Collection直接实现Iterator接口,势必导致集合对象中包含当前迭代位置的数据(指针)。 当集合在不同方法间被传递时,由于当前迭代位置不可预置,那么next()方法的结果会变成不可预知。 除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 但即时这样,Collection也只能同时存在一个当前迭代位置。 而Iterable则不然,每次调用都会返回一个从头开始计数的迭代器。 多个迭代器是互不干扰的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package java.lang;
public interface Iterable<AnyType>{
Iterator<AnyType> iterator();
}
packge java.util;
public interface Iterator<AnyType>{
boolean hasNext();
AnyType next();
void remove();//三个接口
}

3.运用于匿名内部类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Customer{
private static long counter=1;
private final long id=counter++;
private Customer(){}
public String toString(){return "Customer "+id;}
public static Generator<Customer> generator(){
return new Generator<Customer>(){
public Customer next(){return new Customer();}
};
}
}

可以看到,Customer类中的generator方法有了static修饰,不能用继承接口Generator实现方法。可以通过泛型来做到这点。

4.擦除

什么是擦除?

我们可以声明ArrayList.class,但是不能调用ArrayList.class,看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.*;
public class ErasedTypeEquivalence {
public static void main(String[] args) {
Class c1 = new ArrayList<String>().getClass();
Class c2 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
}
}/* Output:
true
*///:~

两个我们看来不同的类型ArrayList和ArrayList的Class却是相同的。再看下面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class HasF {
public void f() { System.out.println("HasF.f()"); }
}
class Manipulator<T> {
private T obj;
public Manipulator(T x) { obj = x; }
// Error: cannot find symbol: method f():
public void manipulate() { obj.f(); }
}
public class Manipulation {
public static void main(String[] args) {
HasF hf = new HasF();
Manipulator<HasF> manipulator =
new Manipulator<HasF>(hf);
manipulator.manipulate();
}
} ///

上述代码会报错,原因是Java运用了擦除,就是说在泛型代码运行时是将类型T擦掉的,一直向上替换到边界,没指定上边界就会换到Object.比如说上例中obj就无法调用.f()。简而言之:

在泛型代码内部,无法获得任何泛型参数类型的信息

我们需要通过边界来让他接受这个类型是有这个调用方法的。

在泛型参数T后加上extends HasF,表示这个参数是HasF的类型或者子类,这样就肯定有.f()方法。

另,在泛型中不要创建数组,例如T[]最好用ArrayList代替,如果需要推荐用Array.newInstance(kind,size).

5.边界

语法定义:

T extends classA&interfaceB&interfaceC&…//一定要按照这种顺序写

6.运用通配符

我们在表示两个List,List时,虽然Cat继承自Animal,但这两个类型没有继承关系,因此通过通配符达到这种效果:

如果B是A的子类,那么List<? extends B>是List<? extends A>的子类

赏

谢谢你请我吃糖果

  • JAVASE

扫一扫,分享到微信

微信分享二维码
Java学习笔记7
Java学习笔记5
© 2018 mhcoderwl
Hexo Theme Yilia by Litten
  • 所有文章
  • 友链
  • 关于我

tag:

  • unp
  • unix
  • socket
  • JAVASE
  • apue
  • muduo
  • c++
  • stl
  • c/c++
  • 编译器
  • C--
  • c
  • FakeCC
  • python
  • sql
  • web 开发
  • Flask框架
  • 算法
  • 面试
  • linux
  • 教程
  • hexo
  • 博客
  • sockets
  • 服务器

    缺失模块。
    1、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    2、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: true
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true
    

  • 昊师兄的博客
目前在东南大学读研
擅长c/c++,linux,shellscript
做一些3D人脸识别的研究
有兴趣一起交流学习!