Java泛型及实践

代码及说明:

  1 package com.zsm.crazyjava;
  2 
  3 import java.util.ArrayList;
  4 import java.util.Collection;
  5 import java.util.List;
  6 import java.util.Set;
  7 
  8 /**
  9  * @author zsm
 10  * @date 2016年11月2日 下午11:23:30
 11  * @version 1.0
 12  * @parameter
 13  * @return
 14  */
 15 // JDK5开始支持泛型。泛型(类、接口、方法);泛型通配符、通配符上限、通配符下限
 16 public class _16_Generic {
 17     // 泛型
 18     List<String> strListStand = new ArrayList<String>();
 19     // 泛型菱形语法(JDK7后初始化时泛型的具体类型可省略,自动判断)
 20     List<String> strList = new ArrayList<>();
 21 
 22     // 泛型类、接口
 23     public interface Fruit<T> {
 24         void add(T fruit);
 25     }
 26 
 27     public interface MyMap<K, V> {
 28         Set<K> keySet();
 29 
 30         V put(K key, V value);
 31     }
 32 
 33     public static class Apple<T> {
 34         private T info;
 35 
 36         public Apple() {// 不能再写成Apple<T>
 37 
 38         }
 39 
 40         public Apple(T info) {
 41             this.info = info;
 42         }
 43 
 44         public T getInfo() {
 45             return this.info;
 46         }
 47 
 48         // 静态方法、静态初始化块、静态变量声明和初始化中不能使用泛型形参,静态类或接口定义处则可以
 49         // static T name;//报错
 50         // public static void bar(T msg) {}
 51         // static {T name = "xiaoming";}
 52 
 53         // 泛型方法则可以使用类型形参,即使是静态方法。类型形参放在方法修饰符和返回值之间
 54         public static <E, F> void ttt(E name, F age) {
 55             ;
 56         }
 57     }
 58 
 59     // 泛型派生的子类、实现泛型接口的类的声明中不能再包含泛型形参
 60     public class A1 extends Apple<String> {// 不能再写成Apple<T>
 61         public String getInfo() {
 62             return super.info;
 63         }
 64     }
 65 
 66     // 带泛型形参的类不会随着类型实参的不同而成为不同的类,接口亦然
 67     static void testClassEqual() {
 68         System.out.println((new Apple<String>()).getClass() == (new Apple<Integer>()).getClass());// true
 69         List<String> strList = new ArrayList<>();
 70         List<Integer> intList = new ArrayList<>();
 71         System.out.println(strList.getClass() == intList.getClass());// true
 72     }
 73 
 74     // 若Foo是Bar的子类,则Foo[]是Bar[]的子类,但List<Foo>却不是List<Bar>的子类。可以使用泛型通配符:?,
 75     public void wildcardTest1(List<Object> c) {// 调用时只能传入List<Object>参数,不可传入List<String>等参数,因为后者不是前者的子类
 76         for (int i = 0; i < c.size(); i++) {
 77             System.out.println(c.get(i));
 78         }
 79     }
 80 
 81     public void wildcardTest2(List<?> c) {// 此时可传入List<String>等参数,但只可从c读不可往里写,因为c类型不定。即带类型通配符定义的对象只可读不可写
 82         for (int i = 0; i < c.size(); i++) {
 83             System.out.println(c.get(i));
 84             // c.add(new Object());//编译错误,不可往c里写,因为c里元素类型未定
 85         }
 86     }
 87 
 88     // 类型通配符上限
 89     public abstract class Shape {
 90         public abstract void draw(MyCanvas c);
 91     }
 92 
 93     public class Circle extends Shape {
 94         @Override
 95         public void draw(MyCanvas c) {
 96             // TODO Auto-generated method stub
 97             System.out.println("draw a circle on " + c);
 98         }
 99     }
100 
101     public class Rectangle extends Shape {
102         @Override
103         public void draw(MyCanvas c) {
104             // TODO Auto-generated method stub
105             System.out.println("draw a rectangle on " + c);
106         }
107     }
108 
109     public class MyCanvas {
110         public void drawAll0(List<?> shapes) {// 使用通配符时类型未定,所以访问每个元素只能用终极父类Object,这导致得进行麻烦的强制类型转换
111             for (Object obj : shapes) {
112                 Shape s = (Shape) obj;
113                 s.draw(this);
114             }
115         }
116 
117         public void drawAll1(List<? extends Shape> shapes) {// 使用通配符上限,从而知道元素元素类型的终极父类是Shape,这样不用进行强转。至多可以有一个类上限、多个接口上限,类上限需放最前。
118             for (Shape s : shapes) {
119                 s.draw(this);
120             }
121         }
122     }
123 
124     // 泛型方法:方法中所用类型形参不要求在类声明中先出现该类型形参;类型形参位于方法修饰符和返回值之间;与泛型类、接口不同的是,无须在调用泛型方法时显式指明实参类型
125     public <T> void fromArrayToCollection(T[] a, Collection<T> c) {// a的实参可以是T[]的子类型
126         for (T o : a) {
127             c.add(o);
128         }
129     }
130 
131     public void test_fromArrayToCollection() {
132         fromArrayToCollection((new Object[10]), new ArrayList<Object>());
133         fromArrayToCollection((new Integer[10]), new ArrayList<Object>());
134         fromArrayToCollection((new Integer[10]), new ArrayList<>());// 与泛型类、接口不同的是,无须在调用泛型方法前显式指明实参类型(指在方法名前),编译器自己确定
135         fromArrayToCollection((new Integer[10]), new ArrayList<Number>());
136         // fromArrayToCollection((new Integer[10]), new ArrayList<String>());//编译错误
137     }
138 
139     // 泛型方法和类型通配符:方法参数间或返回值与参数间存在类型依赖关系(如子类)时采用泛型方法,否则类型参数只用一次,没有存在的必要,可以改用类型通配符。
140     public <T, S extends T> void copy1(List<T> des, List<S> src) {// S仅用了一次且与其他参数间没有依赖关系,因此没有存在的必要,改为下面的方法。
141         for (S s : src) {
142             des.add(s);
143         }
144     }
145 
146     public <T> void copy2(List<T> des, List<? extends T> src) {// 去掉S,改为使用类型通配符上限。
147         for (T t : src) {
148             des.add(t);
149         }
150     }
151 
152     // 泛型方法 ———— 泛型构造器
153     class Foo<E> {
154         public <T> Foo(T t) {
155             System.out.println(t);
156         }
157 
158         public void add(E e) {
159 
160         }
161     }
162 
163     public void test_genericConstructor() {
164         new Foo("good");
165         new Foo(1);
166         new<String> Foo("good");// 显示指定构造方法类型形参的实际类型
167         new<String> Foo<Integer>("good");// 又指定了类的类型形参的实际类型
168         new Foo<>("good");// 菱形语法
169         // new<String> Foo<>(1);// 如果显示指定了构造器类型形参的类型,则不可用菱形语法
170 
171         Foo<Integer> p1 = new<String> Foo("good");
172         Foo<Integer> p2 = new<String> Foo<Integer>("good");
173         Foo<Integer> p3 = new Foo<Integer>("good");
174         // Foo<Integer> p4 = new<String> Foo<>("good");//如果显示指定了构造器类型形参的类型,则不可用菱形语法
175     }
176 
177     // 类型通配符下限。
178     // 返回最后一个元素,类型不可丢。上面的copy2方法如果要返回最后一个被复制的元素,则返回的会是des中元素的类型T,这样就丢失了src的类型即S。可以通过修改copy1解决,也可以通过通配符下限解决。
179     public <T, S extends T> S copy3(List<T> des, List<S> src) {// S仅用了一次且与其他参数间没有依赖关系,因此没有存在的必要,改为下面的方法。
180         int i = 0;
181         for (i = 0; i < src.size(); i++) {
182             des.add(src.get(i));
183         }
184         return src.get(i - 1);
185     }
186 
187     public <T> T copy4(List<? super T> des, List<T> src) {// 去掉S,改为类型通配符下限。
188         int i = 0;
189         for (i = 0; i < src.size(); i++) {
190             des.add(src.get(i));
191         }
192         return src.get(i - 1);
193     }
194 
195     // 檫除与转换:带泛型声明的类间转换
196     public static void test_Transform() {
197         List list;// 不指定实际类型参数,为raw type,默认为上限类型,此为Object
198         List<Integer> listInteger = new ArrayList<Integer>();
199         listInteger.add(1);
200         listInteger.add(2);
201         list = listInteger;// List<Integer>对象赋给未指定类型的List,原始类型丢失,变为Object
202 
203         List<String> listStr = list;// 编译没问题,只有警告:"未经检查的转换"
204         System.out.println(listStr.get(0));// 但访问里面元素,会发生运行时异常
205     }
206 
207     public static void main(String[] args) {
208         // TODO Auto-generated method stub
209 
210     }
211 
212 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
泛型Java中的一个非常重要的特性,它可以让我们在编写代码时更加灵活和安全。泛型可以帮助我们避免类型转换的麻烦,并且可以让我们在编译时就发现类型不匹配的错误。 在Java中,泛型可以应用到类、接口、方法等各种场景中。我们可以通过在类或方法的声明中添加泛型参数来实现泛型。比如,下面是一个用于存储字符串的泛型类的示例: ``` public class MyList<T> { private List<T> list = new ArrayList<T>(); public void add(T item) { list.add(item); } public T get(int index) { return list.get(index); } } ``` 在这个示例中,我们使用了一个泛型参数T来表示该类可以存储任意类型的数据。在add方法中,我们可以用T来代替具体的类型,从而实现了类型安全的添加操作。而在get方法中,我们同样可以使用泛型参数T来表示返回值的类型。 除了泛型Java中的集合也是一个非常常用的特性。集合可以让我们更加方便地管理和处理数据,而且还提供了很多便捷的操作方法。Java中的集合框架包括了List、Set、Map等多种类型,每种类型都有其特定的用途和方法。 比如,List是一种有序的集合类型,可以通过下标来访问其中的元素。而Set是一种无序的集合类型,它可以用于去重或者判断某个元素是否存在。而Map则是一种键值对的集合类型,可以用于快速查找或者存储数据。 在使用集合时,我们需要注意一些细节。比如,集合中存储的元素类型必须是对象类型,而不能是基本类型。同时,在进行集合操作时,我们也需要注意线程安全和并发访问的问题。 总之,泛型和集合是Java中非常重要的特性,它们可以帮助我们更加灵活和安全地编写代码。我们需要在实践中不断学习和总结,提高自己的编程能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值