B站视频指路:尚硅谷Java入门视频教程(在线答疑+Java面试真题)_哔哩哔哩_bilibili
写在前面:马上秋招,开个知识点记录贴,就当做课堂笔记吧.
·泛型:标签
·举例:·中药店 每个抽屉外面贴着标签
·超市购物架上很多瓶子,每个瓶子装的是什么,有标签
·泛型的设计背景
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,JDK1.5之后使用泛型来解决,因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做感性.Collection<E>,List<E>,ArrarList<E>这个<E>是类型参数,即泛型.
泛型的概念
·所谓泛型,就是允许在定义类、接口时通过一个标识标识类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)
·从JDK1.5以后,Java引入了"参数化类型"的概念,允许我们在创建集合时再指定集合元素的类型,正如List<Striing>,这表明该List只能保存字符串类型的对象
·JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参
为什么要有泛型,直接Object不也可以存储数据吗?
1.解决元素存储的安全性问题,好比商品、药品标签,不会弄错
2.解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药品都要辨别
例:在集合中使用泛型的情况 ArrayList
import org.junit.Test; import java.util.ArrayList; public class GenericTest { @Test public void test(){ ArrayList arrayList = new ArrayList(); //存放学生的成绩 arrayList.add(1); arrayList.add(2); arrayList.add(3); arrayList.add(4); //问题一:类型不安全 arrayList.add("Z"); for (Object score : arrayList) { //问题二:强转时 可能出现 类型转换异常 int stuScore = (int) score; System.out.println(stuScore); } } }
1.使用泛型后 增强型 for 循环输出
2.使用泛型后 迭代器输出
例:在集合中使用泛型的情况 HashMap
@Test public void test(){ Map<String,Integer> hashMap = new HashMap<String,Integer>(); hashMap.put("ZK1",1); hashMap.put("ZK3",1); hashMap.put("ZK2",2); //泛型的嵌套 Entry是一个内部的接口 所以需要 Map.Entry 省略Map的话需要import Map Set<Map.Entry<String, Integer>> entries = hashMap.entrySet(); Iterator<Map.Entry<String, Integer>> iterator = entries.iterator(); while (iterator.hasNext()){ Map.Entry<String, Integer> next = iterator.next(); String key = next.getKey(); Integer value = next.getValue(); System.out.println(key + "---->" + value); } }
jdk7新特性:类型推断
Map<String,Integer> hashMap = new HashMap<>(); 后面的尖括号内容可以省略
在集合中使用泛型:
①集合接口或集合类在jdk5.0时都修改为带泛型的结构
②在实例化集合类时,可以指明具体的泛型类型
③指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性)使用到类的泛型的位置,都指定为实例化的泛型.比如: add(E e)--->实例化后:add(Integer e)
④泛型的类型必须是类 不能是基本数据类型 需要用到基本数据类型的位置 用包装类替换
⑤如果实例化时,没有指明泛型的类型 默认类型为 java.lang.Object类型
一些例子:
例题:
Employee.java
public class Employee implements Comparable{ private String name; private int age; private MyDate birthday; public Employee(String name, int age, MyDate birthday) { this.name = name; this.age = age; this.birthday = birthday; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public MyDate getBirthday() { return birthday; } public void setBirthday(MyDate birthday) { this.birthday = birthday; } @Override public int compareTo(Object o) { Employee e = (Employee) o; if(this.getBirthday().getYear()>e.getBirthday().getYear()){ return -1; } if(this.getBirthday().getMonth()>e.getBirthday().getMonth()){ return -1; } return this.getBirthday().getDay()-e.getBirthday().getDay(); } @Override public String toString() { return "Employee{" + "name='" + name + '\'' + ", age=" + age + ", birthday=" + birthday + '}'; } }
MyDate.java
public class MyDate { private int year; private int month; private int day; public MyDate(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } @Override public String toString() { return "MyDate{" + "year=" + year + ", month=" + month + ", day=" + day + '}'; } }
test.java
import org.junit.Test; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class test { @Test public void test(){ MyDate d1 = new MyDate(1996,9,19); MyDate d2 = new MyDate(1997,8,24); MyDate d3 = new MyDate(1999,4,17); TreeSet<Employee> treeSet = new TreeSet<>(); treeSet.add(new Employee("zk",20,d1)); treeSet.add(new Employee("tjw",18,d3)); treeSet.add(new Employee("zzz",13,d2)); Iterator<Employee> iterator = treeSet.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); } System.out.println("*****************************"); Comparator<Employee> comparator = new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { Employee e1 = (Employee) o1; Employee e2 = (Employee) o2; return e1.getName().compareTo(e2.getName()); } }; TreeSet<Employee> treeSet2 = new TreeSet<>(comparator); treeSet2.add(new Employee("zk",20,d1)); treeSet2.add(new Employee("tjw",18,d3)); treeSet2.add(new Employee("zzz",13,d2)); Iterator<Employee> iterator2 = treeSet2.iterator(); while (iterator2.hasNext()){ System.out.println(iterator2.next()); } } }
如何自定义泛型结构:泛型类、泛型接口;泛型方法
1.关于 泛型类、泛型接口:
Order.java
/*
自定义泛型类
*/
public class Order <T>{
String name;
int id;
//类的内部结构就可以使用类的泛型
T orderT;
public Order() {
}
public Order(String name, int id, T orderT) {
this.name = name;
this.id = id;
this.orderT = orderT;
}
public T getOrderT() {
return orderT;
}
public void setOrderT(T orderT) {
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"name='" + name + '\'' +
", id=" + id +
", orderT=" + orderT +
'}';
}
}
import org.junit.Test;
public class ttest {
@Test
public void test(){//如果定义了泛型类 实例化没指明类的泛型 则认为此泛型类型为Object类型
//要求:若定义了类是带泛型的 建议在实例化时 要指明类的泛型
Order order = new Order();
order.setOrderT(123);
order.setOrderT("zk");//建议:实例化时指明类的泛型
Order<String> order1 = new Order<>("Z",1,"K");
}
}
SubOrder.java(已经指明了泛型类型 所以SubOrder不再是一个反省类 就是一个普通类)
public class SubOrder extends Order<Integer>{
}
SubOrder1.java(SubOrder1<T> 仍然是泛型类)
public class SubOrder1<T> extends Order<T>{
}
①泛型类可能有多个参数 此时应将多个参数一起放在尖括号内 比如<E1,E2,E3>
②泛型类的构造器如下:publicGenericCLlass(){}
而这个是错误的:public GenericClass<E>(){}
③实例化后 操作原来泛型位置的结构必须与指定的泛型类型一致
④泛型不同的引用不能相互赋值
尽管在编译时ArrayList<String>和ArrayList<Integer>是两种类型 但在运行时 只有一
个ArrayList被加载到JVM中
⑤泛型如果不指定 将会被擦除 泛型对应的类型均按照Object处理 但不等价于Object.
经验:泛型要使用一路都用 要不用 一路都不用
⑥如果泛型接口是一个接口或抽象类 则不可创建泛型类的对象
⑦jdk1.7 泛型的简单化操作 ArrayList<Fruit> fist = new ArrayList<>();
⑧泛型的指定中不能使用基本数据类型 可以使用包装类替换
⑨在类/接口上声明的泛型 在本类或本接口中即代表某种类型 可以作为非静态属性的类型、非静态方法的参数类型、非静态方法的返回值类型.但在静态方法中不能使用类的泛型
tips:类的泛型 是造对象的时候(实例化) 指定的 而静态结构要早于对象的创建 所以错了
⑩异常类不能是泛型的
另:
①不能使用new E[ ] . 但是可以:E[ ] elements = (E[ ])new Object[capacity]
参考:ArrayList源码中声明:Object[ ] elementData 而非泛型参数类型数组
②父类有泛型,子类可以选择保留泛型也可以指定泛型类型
·子类不保留父类的泛型:按需实现
1.没有类型 擦除
2.具体类型
·子类保留父类的泛型:泛型子类
1.全部保留
2.部分保留
结论:子类必须是"富二代" 子类除了指定或保留父类的泛型 还可以增加自己的泛型
泛型方法:在方法中出现了泛型的结构,泛型的参数与类的泛型参数没有任何关系,
即:泛型方法所属的类是不是泛型类都没有关系
泛型方法可以声明为静态的 因为泛型参数是在调用方法时确定的 并非实例化类时确定的
下面这个是泛型方法:
这个也是
泛型在继承方面的体现
①类A是类B的父辈,G<A>和G<B>不具有子父类关系 二者是并列关系
补充:类A是类B的父类,A<G>是B<G>的父类
前两个体现了多态 后两个报错 是一样的异常类型
此时的list1和list2是并列的关系 不具有子父类的关系
通配符的使用:
通配符:?
类A是类B的父类 G<A>和G<B>是没有关系的 二者的共同父类是G<?>
import org.junit.Test; import java.util.*; public class GenericTest { @Test public void test() { List<Object> list1 = null; List<String> list2 = null; List<String> list3 = new ArrayList<>(); List<?> list = null; list = list1; list = list2; list3.add("zhang"); list3.add("ke"); list = list3; //添加(写入):对于List<?>就不能向其内部添加数据 //但是只可以添加null //list.add("ZZ"); list.add(null); //获取(读取):允许读取 读取的类型为Object Object o = list.get(0); System.out.println(o); print(list); // print(list1); // print(list2); } public void print(List<?> list){ Iterator<?> iterator = list.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } } }
有限制的通配符:
·通配符指定上限:
上限extends:使用时指定的类型必须是继承某个类,活着实现某个接口,即<=
下限super:使用时指定的类型不能小于操作的类,即>=
举例:
<? extends Number> (无穷小,Number]
只允许泛型为Number及Number子类的引用调用
<? super Number> [Number,无穷大}
只允许泛型为Number及Number父类的引用调用
<? extends Comparable>
只允许泛型为实现Comparable接口的实现类的引用调用extends---> <=
super---> >=
import org.junit.Test; import java.util.*; public class GenericTest { @Test public void test() { List<? extends person> list1 = null; List<? super person> list2 = null; List<student> list3 = new ArrayList<>(); List<person> list4 = new ArrayList<>(); List<Object> list5 = new ArrayList<>(); list1 = list3; list1 = list4; list2 = list4; list2 = list5; //读取数据 list1 = list3; person person = list1.get(0); student s = list1.get(0); //报错 因为extends是小于等于 所以list1里的元素至少应该是person 才能同时包括person和student list2 = list4; Object object = list2.get(0); person pers1 = list2.get(0); //报错 因为 super是大于等于 所以list2里的元素还可能是person的父类的实例化对象 所以只能是Object } } class person{ } class student extends person{ }
写入数据的话 extends不可以 super可以(Number和Number的子类)
例题:
DAO.java
import java.util.*; public class DAO <T>{ private Map<String,T> map = new HashMap<String,T>(); public void save(String id,T entity){ map.put(id,entity); } public T get(String id){ return map.get(id); } public void update(String id,T entity) { if(map.containsKey(id)){ map.put(id,entity); } } public List<T> list(){ // Collection<T> values = map.values(); // return (List<T>) values; 错的 List<T> list = new ArrayList<>(); Collection<T> values = map.values(); for(T t : values){ list.add(t); } return list; } public void delete(String id){ map.remove(id); } }
User.java
import java.util.Objects; public class User{ private int id; private int age; private String name; public User(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "id=" + id + ", age=" + age + ", name='" + name + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; User user = (User) o; return id == user.id && age == user.age && Objects.equals(name, user.name); } }
DAOTest.java
import org.junit.Test; import java.util.List; public class DAOTest { @Test public void test(){ DAO<User> dao = new DAO<User>(); dao.save("1001",new User(1001,22,"tjw")); dao.save("1002",new User(1002,23,"zk")); dao.save("1003",new User(1003,24,"z")); dao.update("1003",new User(1003,3,"zhangke")); List<User> list = dao.list(); list.forEach(System.out::println); System.out.println("************************"); dao.delete("1001"); List<User> list2 = dao.list(); list2.forEach(System.out::println); } }
练习:
1.如何遍历Map的Key集 value集 key-value集 使用上泛型
import org.junit.Test;
import java.util.*;
public class fanxing {
@Test
public void test(){
Map<Integer,Integer> map = new HashMap<>();
map.put(1,11);
map.put(2,22);
map.put(3,33);
map.put(4,44);
map.put(5,55);
Set<Integer> set = map.keySet();
for (Integer i :set) {
System.out.println(i);
}
Collection<Integer> collection = map.values();
Iterator<Integer> iterator = collection.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
Set<Map.Entry<Integer,Integer>> entries = map.entrySet();
Iterator<Map.Entry<Integer, Integer>> iterator1 = entries.iterator();
while (iterator1.hasNext()){
Map.Entry<Integer,Integer> entry = iterator1.next();
Integer k = entry.getKey();
Integer v = entry.getValue();
System.out.println(k + "--->" + v);
}
}
}
2.写出使用Iterator和增强for循环遍历List<String>的代码 使用泛型
import org.junit.Test;
import java.util.*;
public class fanxing {
@Test
public void test(){
List<String> list = new ArrayList<>();
for (String s:list
) {
System.out.println(s);
}
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
3.提供一个方法 用于遍历获取HashMao<String,String>中的所有value 并存放在List中返回,
考虑上集合中泛型的使用
import java.util.*;
public class fanxing<String> {
public List<String> list(HashMap<String,String> map){
ArrayList<String> list = new ArrayList<>();
Collection<String> values = map.values();
for (String t:values
) {
list.add(t);
}
return list;
}
}