(一)泛型(上) 1)No泛型
public class NeedGeneric1 {
private static int add(int a, int b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}private static float add(float a, float b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}private static double add(double a, double b) {
System.out.println(a + "+" + b + "=" + (a + b));
return a + b;
}private static double add(T a, T b) {
System.out.println(a + "+" + b + "=" + (a.doubleValue() + b.doubleValue()));
return a.doubleValue() + b.doubleValue();
}public static void main(String[] args) {
NeedGeneric1.add(1, 2);
NeedGeneric1.add(1f, 2f);
NeedGeneric1.add(1d, 2d);
NeedGeneric1.add(Integer.valueOf(1), Integer.valueOf(2));
NeedGeneric1.add(Float.valueOf(1), Float.valueOf(2));
NeedGeneric1.add(Double.valueOf(1), Double.valueOf(2));
}
}
我们不难发现,同一个add方法,我们需要写要几个不同参数形式的方法去适配所有的情况,这无疑是十分不方便的。
2)Have泛型
package com.jay.java.泛型.DefineGeneric;
public class GenericClass {
private T data;
public T getData() {
return data;
}public void setData(T data) {
this.data = https://www.it610.com/article/data;
}public static void main(String[] args) {
GenericClass> genericClass=new GenericClass<>();
genericClass.setData("Generic Class");
System.out.println(genericClass.getData());
}
}
3)泛型的意义
- 适用于多种数据类型执行相同的代码(代码复用)
- 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
package lys.genericityup.Bean;
public class Car {
private T car;
public Car(T car){
this.car = car;
}public T getObject() {
return this.car;
}
}
测试方法
package lys.genericityup.test;
import lys.genericityup.Bean.Car;
import org.junit.Test;
import java.util.Date;
public class TestMain {@Test
public void testCar(){
Car> car = new Car<>("Bus");
System.out.println(car.getObject());
Car car2 = new Car(new Date());
System.out.println(car2.getObject());
}
}
(二)泛型(下) 1) 泛型的继承规则
- 对于泛型参数是继承关系的泛型类之间是没有继承关系的
- 泛型类可以继承其它泛型类,例如:
public class Car
extends Vehicle - 泛型类的继承关系在使用中同样会受到泛型类型的影响
package lys.genericitydown.bean;
public class Car extends Vehicle{public Car(T name) {
super(name);
}
}
Vehicle类
package lys.genericitydown.bean;
public class Vehicle {
private T name;
public Vehicle(T name) {
this.name = name;
}@Override
public String toString() {
return "Vehicle{" +
"name=" + name +
'}';
}
}
Test类
package lys.genericitydown.test;
import lys.genericitydown.bean.Car;
import org.junit.Test;
import javax.xml.crypto.Data;
import java.util.Date;
public class TestMain {
@Test
public void test01(){
System.out.println(new Car>("BMW").toString());
}}
3) 泛型的通配符问题
- extends Parent>指定了泛型类型的上级
- super Child>指定了泛型类型的下级
- >指定了没有限制的泛型类型
文章图片
4)参考代码
public class GenericByWildcard {
private static void print(GenericClass fruitGenericClass) {
System.out.println(fruitGenericClass.getData().getColor());
}private static void use() {
GenericClass fruitGenericClass = new GenericClass<>();
print(fruitGenericClass);
GenericClass orangeGenericClass = new GenericClass<>();
//类型不匹配,可以使用 extends Parent> 来解决
//print(orangeGenericClass);
}/**
* extends Parent> 指定了泛型类型的上届
*/
private static void printExtends(GenericClass extends Fruit> genericClass) {
System.out.println(genericClass.getData().getColor());
}public static void useExtend() {
GenericClass fruitGenericClass = new GenericClass<>();
printExtends(fruitGenericClass);
GenericClass orangeGenericClass = new GenericClass<>();
printExtends(orangeGenericClass);
GenericClass foodGenericClass = new GenericClass<>();
//Food是Fruit的父类,超过了泛型上届范围,类型不匹配
//printExtends(foodGenericClass);
//表示GenericClass的类型参数的上届是Fruit
GenericClass extends Fruit> extendFruitGenericClass = new GenericClass<>();
Apple apple = new Apple();
Fruit fruit = new Fruit();
/*
* 道理很简单,? extends X表示类型的上界,类型参数是X的子类,那么可以肯定的说,
* get方法返回的一定是个X(不管是X或者X的子类)编译器是可以确定知道的。
* 但是set方法只知道传入的是个X,至于具体是X的那个子类,不知道。
* 总结:主要用于安全地访问数据,可以访问X及其子类型,并且不能写入非null的数据。
*/
//extendFruitGenericClass.setData(apple);
//extendFruitGenericClass.setData(fruit);
fruit = extendFruitGenericClass.getData();
}/**
* super Child> 指定了泛型类型的下届
*/
public static void printSuper(GenericClass super Apple> genericClass) {
System.out.println(genericClass.getData());
}public static void useSuper() {
GenericClass foodGenericClass = new GenericClass<>();
printSuper(foodGenericClass);
GenericClass fruitGenericClass = new GenericClass<>();
printSuper(fruitGenericClass);
GenericClass appleGenericClass = new GenericClass<>();
printSuper(appleGenericClass);
GenericClass hongFuShiAppleGenericClass = new GenericClass<>();
// HongFuShiApple 是Apple的子类,达不到泛型下届,类型不匹配
//printSuper(hongFuShiAppleGenericClass);
GenericClass orangeGenericClass = new GenericClass<>();
// Orange和Apple是兄弟关系,没有继承关系,类型不匹配
//printSuper(orangeGenericClass);
//表示GenericClass的类型参数的下界是Apple
GenericClass super Apple> supperAppleGenericClass = new GenericClass<>();
supperAppleGenericClass.setData(new Apple());
supperAppleGenericClass.setData(new HongFuShiApple());
/*
* ? superX表示类型的下界,类型参数是X的超类(包括X本身),
* 那么可以肯定的说,get方法返回的一定是个X的超类,那么到底是哪个超类?不知道,
* 但是可以肯定的说,Object一定是它的超类,所以get方法返回Object。
* 编译器是可以确定知道的。对于set方法来说,编译器不知道它需要的确切类型,但是X和X的子类可以安全的转型为X。
* 总结:主要用于安全地写入数据,可以写入X及其子类型。
*/
//supperAppleGenericClass.setData(new Fruit());
//get方法只会返回一个Object类型的值。
Object data = https://www.it610.com/article/supperAppleGenericClass.getData();
}/**
* > 指定了没有限定的通配符
*/
public static void printNonLimit(GenericClass> genericClass) {
System.out.println(genericClass.getData());
}public static void useNonLimit() {
GenericClass foodGenericClass = new GenericClass<>();
printNonLimit(foodGenericClass);
GenericClass fruitGenericClass = new GenericClass<>();
printNonLimit(fruitGenericClass);
GenericClass appleGenericClass = new GenericClass<>();
printNonLimit(appleGenericClass);
GenericClass> genericClass = new GenericClass<>();
//setData 方法不能被调用, 甚至不能用 Object 调用;
//genericClass.setData(foodGenericClass);
//genericClass.setData(new Object());
//返回值只能赋给 Object
Object object = genericClass.getData();
}}
5)泛型中的约束和局限性
- 不能实例化泛型类
- 静态变量或方法不能引用泛型类型变量,但是静态泛型方法是可以的
- 基本类型无法作为泛型类型
- 无法使用
instanceof
关键字或==判断泛型类的类型 - 泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
- 泛型数组可以声明但无法实例化
- 泛型类不能继承Exception或者
Throwable
- 不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出
1)List
@org.junit.Test
public void test01(){
List list = new ArrayList();
list.add(10);
list.add("hello");
list.add(true);
list.add(99.9f);
/*
第一种遍历方法
*/
for (Object o : list) {
System.out.println(o);
}
/*
第二中遍历方法
*/
Iterator iterator = list.iterator();
while (iterator.hasNext()){
Object next = iterator.next();
System.out.println(next);
}
}
2)
HashSet
【Java重温】HashSet
中没有重复的元素,可以用于去重@org.junit.Test
public void test02(){
/**
* HashSet中没有重复的元素
*/
Set set = new HashSet();
set.add(1);
set.add("Hello");
set.add(1246.4f);
set.add("Hello");
for (Object o : set) {
System.out.println(o);
}
}
3) Queue
@org.junit.Test
public void test03(){
/**
* 不要使用add方法添加
* 相同:两者都是往队列尾部插入元素,
* 不同的:当超出队列界限的时候,add()方法是抛出异常让你处理,而offer()方法是直接返回false
*/
Queue queue = new LinkedList<>();
queue.offer(1);
queue.offer("Hello");
queue.offer(999.9d);
for (Object o : queue) {
System.out.println(o);
}
/**
* peek()方法会返回队列的头部
*/
System.out.println("QueueHead:"+queue.peek());
System.out.println("QueueSize:"+queue.size());
/**
* poll()会把队列的头部取出
*/
System.out.println("QueueHead:"+queue.poll());
System.out.println("QueueSize:"+queue.size());
}
4)
HashMap
@org.junit.Test
public void test04(){
/*
添加键值对到map中去
*/
Map,String> map = new HashMap,String>();
map.put("1a","Hello");
map.put("2b","World");
map.put("3c","Java");
/*
遍历方法一:
只获取出map中的values
*/
System.out.println("打印Values");
for (String value : map.values()){
System.out.println(value);
}
System.out.println("============================");
/*
遍历方法二:
获取出map中的key和value
*/
System.out.println("打印Key:Value");
Set> set = map.keySet();
for (String key : set) {
String value = https://www.it610.com/article/map.get(key);
System.out.println(key+":"+value);
}
System.out.println("============================");
/*
遍历方法三:
最常用的方法
*/
System.out.println("最常用的方式打印");
for (Map.Entry, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = https://www.it610.com/article/entry.getValue();
System.out.println(key+":"+value);
}
}
5)Array
@org.junit.Test
public void test05(){
/**
* 一旦转换是不能修改的
*/
List list = Arrays.asList(1,2,3,4,5,6,7,8,9);
for (Object o : list) {
System.out.println(o);
}System.out.println("List转换为数组");
Object[] objects = list.toArray();
System.out.println(Arrays.toString(objects));
/**
* 把List转换为不能更改的List
*/ArrayList
推荐阅读
- Java|Java基础——数组
- 人工智能|干货!人体姿态估计与运动预测
- java简介|Java是什么(Java能用来干什么?)
- Java|规范的打印日志
- Linux|109 个实用 shell 脚本
- 程序员|【高级Java架构师系统学习】毕业一年萌新的Java大厂面经,最新整理
- Spring注解驱动第十讲--@Autowired使用
- SqlServer|sql server的UPDLOCK、HOLDLOCK试验
- jvm|【JVM】JVM08(java内存模型解析[JMM])
- 技术|为参加2021年蓝桥杯Java软件开发大学B组细心整理常见基础知识、搜索和常用算法解析例题(持续更新...)