(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
Java SE 053 泛型详解
文章目录
1.HashSet底层是利用HashMap去实现的,HashMap底层是用数组实现的
2.Properties类
(1)属性(Properties)是HashTable的一个子类。它用来保持值的列表,在其中关键字和值都是字符串(String)。Properties类被其他的Java类所使用。例如,当获得系统环境时,System.getProperties()返回对象的类型。
package com.javase.properties;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
public class PropertiesTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
Properties p = System.getProperties();
Set set = p.keySet();
for(Iterator iter = set.iterator(); iter.hasNext();){
String key = (String)iter.next();
String value = p.getProperty(key);
System.out.println(key + "=" + value);
}
}
}
3.泛型
3.1泛型要解决的问题
值放进去的时候没有问题,但是取出来时就会发生ClassCastException泛型就是为了解决这个问题的,编译的时候只要不出问题,运行的时候一定不会出问题。
package com.javase.generics;
import java.util.ArrayList;
import java.util.List;
/**
* 值放进去的时候没有问题,但是取出来时就会发生ClassCastException
* 泛型就是为了解决这个问题的,编译的时候只要不出问题,运行的时候一定不会出问题。
*/
public class ArrayListTest {
public static void main(String[] args) {
List list = new ArrayList();
list.add("string");
list.add(new Integer(2));
list.add(new Boolean(false));
String str = (String)list.get(0);
Integer in = (Integer)list.get(1);
String b = (String)list.get(2);
}
}
4.泛型的使用
(1)T并不是java里面的一个类,它叫做泛型,即很广泛的一种类型。
(2)T并不代表一个具体数值本身,它代表的是一些类型的信息,比如说传一个String,String就是一种类型,传一个Integer实例化的时候,T是代表的是类型的信息,需要给它提供类型的信息。即在实例化类时要传递一个具体的类型。
package com.javase.generics;
public class GenericFoo<T> {
private T foo;
public T getFoo() {
return foo;
}
public void setFoo(T foo) {
this.foo = foo;
}
public static void main(String[] args) {
GenericFoo<Boolean> foo1 = new GenericFoo<Boolean>();
GenericFoo<Integer> foo2 = new GenericFoo<Integer>();
foo1.setFoo(new Boolean(true));
foo2.setFoo(new Integer(2));
Boolean b = foo1.getFoo();
Integer integer = foo2.getFoo();
System.out.println(b+" "+integer);
}
}
5.泛型的定义与使用
5.1泛型定义在类上
(1)泛型类:把泛型定义在类上,用户在使用该类的时候,才清楚该类具体是什么类型。
(2)使用的时候确定了该类的类型,就不用担心强转的问题,也就不用担心的在运行时类型转换异常的问题了。
(3)用户想要使用哪种类型,就在创建的时候指定类型。使用的时候,该类就会自动转换成用户想要使用的类型
package com.javareview.generic;
public class GenericObj<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
5.2泛型类的使用
package com.javareview.generic;
public class GenericTest {
public static void main(String[] args) {
//s1.在使用时确定泛型类是什么具体类型,此处为String类型
GenericObj<String> genericObj = new GenericObj<>();
genericObj.setObj("xiongjie");
//s2.在使用的时候,该类会自动转换成用户指定的类型了
String name = genericObj.getObj();
System.out.println(name);
//s3.在使用时确定泛型类是什么具体类型,此处为Integer类型
GenericObj<Integer> genericInteger = new GenericObj<Integer>();
genericInteger.setObj(10);
//s4.使用的时候,该类就会自动转换成用户想要使用的类型了
Integer age = genericInteger.getObj();
System.out.println(age);
}
}
5.2泛型方法
(1)在类上定义的泛型,在方法中也可以使用
(2)仅仅在某一个方法上需要使用泛型,外界仅仅是关心该方法,不关心类其他的属性,这样的话在整个类上定义泛型,未免就有些大题小作了。
5.2.1定义泛型方法
(1)定义泛型方法
(2)泛型是先定义后使用的
package com.javareview.generic;
public class GenericMethod {
//用户传递进泛型方法的是什么类型,方法返回值就是什么类型
public <T> void show(T t) {
System.out.println(t);
}
}
5.2.2泛型方法的使用
public class GenericMethodTest {
public static void main(String[] args) {
GenericMethod gm = new GenericMethod();
//s1.用户传递进泛型方法的是什么类型,方法返回值就是什么类型
gm.show("张三");
gm.show(22);
gm.show(12.5);
}
}
6.泛型类派生出的子类
(1)泛型类是拥有泛型这个特性的类,它本质上还是一个Java类,那么它就可以被继承。
(2)那它是怎么被继承的呢?这里分两种情况
6.1子类明确泛型类的类型参数变量
(1)泛型接口
package com.javareview.generic;
/**
* 泛型接口
* @author xiongjie
* @param <T>
*/
public interface GenericInterface<T> {
public abstract void show(T t);
}
(2)实现泛型接口的类
子类明确泛型类的类型参数变量
package com.javareview.generic.test;
import com.javareview.generic.GenericInterface;
/**
* 实现泛型接口的类,子类明确泛型类的类型参数变量
*/
public class GenericInterfaceImpl implements GenericInterface<String>{
@Override
public void show(String t) {
System.out.println(t);
}
}
6.2子类不明确泛型类的类型参数变量
(1)子类明确泛型类的类型参数变量
当子类不清楚泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在子类中需要定义出类型参数变量。
/**
* 当子类不明确泛型类的类型参数变量时,外界使用子类的时候,也需要传递类型参数变量进来,在实现类上需要定义出类型参数变量
*/
public class GenericInterfaceImpl<T> implements GenericInterface<T>{
@Override
public void show(T t) {
System.out.println(t);
}
}
6.3测试这两种情况
package com.javareview.generic.test;
import com.javareview.generic.GenericInterface;
import com.javareview.generic.GenericInterfaceImpl1;
import com.javareview.generic.GenericInterfaceImpl2;
public class GenericInterfaceImplTest {
public static void main(String[] args) {
//s1.测试第一种情况:子类明确泛型类的类型参数变量
GenericInterface<String> gi1 = new GenericInterfaceImpl1();
gi1.show("hello");
//s2测试第二种情况:子类不明确泛型类的类型参数变量
GenericInterface<String> gi2 = new GenericInterfaceImpl2<>();
gi2.show("100");
}
}
6.3.1注意
(1)实现类要是重写父类的方法,返回值的类型是要和父类一样的。
(2)类上声明的泛型只对非静态成员有效。
7.类型通配符
7.1为什么需要类型通配符?
(1)现在有个需求:方法接收一个集合参数,遍历集合并把集合元素打印出来,怎么办?
(2)按照我们没有学习泛型之前,我们可能会这样做:
public void test(List list) {
int i = 0;
for(; i < list.size();i++ ) {
System.out.println(list.get(i));
}
}
(3)上面的代码是正确的,只不过在编译的时候会出现警告,说没有确定集合元素的类型
7.2不够优美的写法
(1)该test()方法只能遍历装载着Object的集合,不够优美
泛型中的<Object>并不是像以前那样有继承关系的,也就是说List<Object>和List<String>是毫无关系的
public void testTpf1(List<Object> list) {
int i = 0;
for(; i < list.size();i++ ) {
System.out.println(list.get(i));
}
}
7.3通配符?
(1)?号通配符表示可以匹配任意类型,任意的Java类都可以匹配
/**
* 通配符的写法
* @param list
*/
public void testTpf(List<?> list) {
//list.add("ccc");只能调对象与类型无关的方法,不能调用对象与类型有关的方法,比如说add()方法,它是与对象类型有关的方法
int i = 0;
for(; i < list.size();i++ ) {
System.out.println(list.get(i));
}
}
(2)现在非常值得注意的是,当我们使用?号通配符的时候:就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
(3)只能调用与对象无关的方法,不能调用对象与类型有关的方法。因为直到外界使用才知道具体的类型是什么。也就是说,在上面的List集合,我是不能使用add()方法的。因为add()方法是把对象丢进集合中,而现在我是不知道对象的类型是什么。
(4)测试代码
public static void main(String[] args) {
GenericTPF genericTpf = new GenericTPF();
//s1.初始化集合
List<String> stringList = new ArrayList<String>();
stringList.add("fff");
stringList.add("aaa");
genericTpf.testTpf(stringList);
}
7.3.1设定通配符上限
(1)首先,我们来看一下设定通配符上限用在哪里
(2)我想接收一个List集合,它只能操作数字类型的元素【Float、Integer、Double、Byte等数字类型都行】,怎么做?
我们学习了通配符,但是如果直接使用通配符的话,该集合就不是只能操作数字了。因此我们需要用到设定通配符上限
List<? extends Number>
上面的代码表示的是:List集合装载的元素只能是Number的子类或自身
public static void main(String[] args) {
GenericTPF genericTpf = new GenericTPF();
//s1.初始化集合
List<String> stringList = new ArrayList<String>();
stringList.add("fff");
stringList.add("aaa");
//s2.测试通配符
genericTpf.testTpf2(stringList);
//s3.测试设置通配符上限
List<Integer> integerList = new ArrayList<Integer>();
integerList.add(1999);
integerList.add(129);
integerList.add(1599);
integerList.add(1939);
List<Float> floatList = new ArrayList<Float>();
floatList.add(12.0F);
floatList.add(13.0F);
floatList.add(14.0F);
floatList.add(15.0F);
List<Double> doubleList = new ArrayList<Double>();
doubleList.add(44.3);
doubleList.add(45.3);
doubleList.add(42.3);
List<Long> longList = new ArrayList<Long>();
longList.add(54L);
longList.add(52L);
longList.add(14L);
longList.add(534L);
genericTpf.testTpf3(integerList);
genericTpf.testTpf3(floatList);
genericTpf.testTpf3(doubleList);
genericTpf.testTpf3(longList);
//genericTpf.testTpf3(stringList); 因为限定了通配符的上限只能是数值类型,所以此处会报错
}
7.3.2设定通配符的下限
(1)传递进来的只能是Type或Type的父类
<? super Type>
(2)在使用泛型过程中限定泛型的下限
public void testTpfSuper() {
//s1.在使用泛型过程中限定泛型的下限
GenericObj<? super List> genericObjList = null;
//s1.以下代码出错,是因为在使用过程中限定了泛型的下限为List集合,所以在构建集合的时候必须是List或List的超类
//genericObjList = new GenericObj<ArrayList>();
genericObjList = new GenericObj<Object>();
}
8.通配符和泛型方法
(1)大多时候,我们都可以使用泛型方法来代替通配符的
//s1.使用通配符
public static void test(List<?> list){
}
//s2.使用泛型方法
public <T> void test2(List<T> list){
}
(2)使用通配符还是使用泛型方法的原则
a.如果参数之间的类型有依赖关系,或者返回值是与参数之间有依赖关系的。那么就使用泛型方法
b.如果没有依赖关系的,就使用通配符,通配符会灵活一些.
9.泛型擦除
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
总结
(1)所谓泛型:就是变量类型的参数化。
(2)解说:不是变量本身,是变量的类型,变量就是一个赋值,它是类型,什么类型,T类型,之前是确定的,现在将其参数化了,只有当构造这个对象的时候才能确定这个T到底是什么类型。
(3)泛型是先定义后使用的