泛型 和 IO流 和 网络编程
文章目录
- 🚏 泛型
- 🚀 泛型的概念
- 🚬 为什么要使用泛型
- 🚄 在集合中使用泛型
- 🚒 自定义泛型结构
- 🚬 泛型类
- 🚭 自定义泛型的子类1
- 🚭 自定义泛型的子类2
- 🚬 泛型接口
- 🚬 泛型方法
- 🚬 实际开发中使用泛型DAO
- 🚤 泛型在继承上的体现
- 🚗 通配符的使用
- 🚬 有限制条件的通配符的使用
😹 作者: gh-xiaohe
😻 gh-xiaohe的博客
😽 觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!
🚏 泛型
泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
🚀 泛型的概念
所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。
🚬 为什么要使用泛型
问题一:类型不安全
问题二:强转时,可能出现ClassCastException
🚄 在集合中使用泛型
- 总结:
- ① 集合接口或集合类在jdk5.0时都修改为带泛型的结构。
- ② 在实例化集合类时,可以指明具体的泛型类型
- ③ 指明完以后,在集合类或接口中凡是定义类或接口时,内部结构(比如:方法、构造器、属性等)使用到类的泛型的位置,都指定为实例化的泛型类型。
- 比如:add(E e) —>实例化以后:add(Integer e)
- ④ 注意点:泛型的类型必须是类,不能是基本数据类型。需要使用到基本数据类型的位置,拿包装类替换
- ⑤ 如果实例化时,没有指明泛型的类型。默认类型为java.lang.Object类型。
未使用泛型
//在集合中使用泛型之前的情况:
@Test
public void test1(){
ArrayList list = new ArrayList();
//需求:存放学生的成绩
list.add(78);
list.add(76);
list.add(89);
list.add(88);
//问题一:类型不安全
// list.add("Tom");
for(Object score : list){
//问题二:强转时,可能出现ClassCastException
int stuScore = (Integer) score;
// int stuScore = (int) score;也可这样
System.out.println(stuScore);
}
}
在集合中使用泛型的情况:以ArrayList为例
//在集合中使用泛型的情况:以ArrayList为例
@Test
public void test2(){
//问什么不能写int:泛型的类型必须是类,不能是基本数据类型。需要用到基本数据类型的位置,拿包装类替换
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(78);
list.add(87);
list.add(99);
list.add(65);
//编译时,就会进行类型检查,保证数据的安全
// list.add("Tom");
//方式一:
// for(Integer score : list){
// //避免了强转操作
// int stuScore = score;
//
// System.out.println(stuScore);
//
// }
//方式二:
Iterator<Integer> iterator = list.iterator();
while(iterator.hasNext()){
int stuScore = iterator.next();
System.out.println(stuScore);
}
}
在集合中使用泛型的情况:以HashMap为例
@Test
public void test3(){
// Map<String,Integer> map = new HashMap<String,Integer>();
//jdk7新特性:类型推断
Map<String,Integer> map = new HashMap<>();
map.put("Tom",87);
map.put("Jerry",87);
map.put("Jack",67);
// map.put(123,"ABC");
//泛型的嵌套
Set<Map.Entry<String,Integer>> entry = map.entrySet();
Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
while(iterator.hasNext()){
Map.Entry<String, Integer> e = iterator.next();
String key = e.getKey();
Integer value = e.getValue();
System.out.println(key + "----" + value);
}
}
🚒 自定义泛型结构
如何自定义泛型结构:泛型类、泛型接口;泛型方法。
🚬 泛型类
public class Order<T> {
String orderName;
int orderId;
//类的内部结构就可以使用类的泛型
T orderT;
public Order(){
}
public Order(String orderName,int orderId,T orderT){
this.orderName = orderName;
this.orderId = orderId;
this.orderT = orderT;
}
@Override
public String toString() {
return "Order{" +
"orderName='" + orderName + '\'' +
", orderId=" + orderId +
", orderT=" + orderT +
'}';
}
}
@Test
public void test1(){
//如果定义了泛型类,实例化没有指明类的泛型,则认为此泛型类型为Object类型
//要求:如果大家定义了类是带泛型的,建议在实例化时要指明类的泛型。
Order order = new _Order();
order.setOrderT(123);
order.setOrderT("ABC");
//建议:实例化时指明类的泛型
Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");
order1.setOrderT("AA:hello");
}
🚭 自定义泛型的子类1
由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
SubOrder1:不是泛型类
public class SubOrder1 extends Order<Integer> { // SubOrder1:不是泛型类
}
@Test
public void test2(){
SubOrder1 sub1 = new SubOrder1();
//由于子类在继承带泛型的父类时,指明了泛型类型。则实例化子类对象时,不再需要指明泛型。
sub1.setOrderT(1122);
SubOrder2<String> sub2 = new SubOrder2<>();
sub2.setOrderT("order2...");
}
🚭 自定义泛型的子类2
SubOrder2: 仍然是泛型类
public class SubOrder2<T> extends Order<T> { // SubOrder2<T>:仍然是泛型类
}
@Test
public void test2(){
SubOrder2<String> sub2 = new SubOrder2<>();
sub2.setOrderT("order2...");
}
🚬 泛型接口
//1.接口中静态成员也不能使用泛型
//2.泛型接口的类型,在继承接口或者实现接口时确定
interface IUsb<U,R>{
int n = 10;
//U name; //name类型默认为 public static final,所以不能使用
//普通方法中可以使用接口泛型
R get(U u);
void hi(R r);
void run(R r1,R r2,U u1,U u2);
//在JDK 8中,可以在接口中,使用默认方法
default R method(U u){
return null;
}
}
//实现接口时,指定泛型类型
class BB implements IUsb<Integer,Float>{
@Override
public Float get(Integer integer) {
return null;
}
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Integer u1, Integer u2) {
}
}
//继承接口时,指定泛型类型
interface IA extends IUsb<String,Double>{
}
class AA implements IA{
@Override
public Double get(String s) {
return null;
}
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
}
🚬 泛型方法
方法,也可以被泛型化,不管此时定义在其中的类是不是泛型类。 在泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型
泛型方法的格式:
- [ 访问权限] < 泛型> 型 返回类型 名 方法名([ 泛型标识 称 参数名称]) 抛出的异常
- 泛型方法,可以声明为静态的。原因:泛型参数是在调用方法时确定的。并非在实例化类时确定。
错误写法:
- public static List copyFromArrayToList(E[] arr){ 编译器会认为有一个类叫E,而不是泛型
public class Order<T> {
// public static List<E> copyFromArrayToList(E[] arr){
// 错误写法:编译器会认为有一个类叫E,而不是泛型
public static <E> List<E> copyFromArrayToList(E[] arr){
ArrayList<E> list = new ArrayList<>();
for(E e : arr){
list.add(e);
}
return list;
}
}
//测试泛型方法
@Test
public void test4(){
Order<String> order = new Order<>();
Integer[] arr = new Integer[]{1,2,3,4};
//泛型方法在调用时,指明泛型参数的类型。
List<Integer> list = order.copyFromArrayToList(arr);
System.out.println(list);
}
🚬 实际开发中使用泛型DAO
DAO:data(base) access object DAO:可以理解为操作数据库的通用操作
DAO
public class DAO<T> {//表的共性操作的DAO
//添加一条记录
public void add(T t){
}
//删除一条记录
public boolean remove(int index){
return false;
}
//修改一条记录
public void update(int index,T t){
}
//查询一条记录
public T getIndex(int index){
return null;
}
//查询多条记录
public List<T> getForList(int index){
return null;
}
//泛型方法
//举例:获取表中一共有多少条记录?获取最大的员工入职时间?
public <E> E getValue(){
return null;
}
}
Customer 和 CustomerDAO 测试
public class Customer { //此类对应数据库中的customers表
}
public class CustomerDAO extends DAO<Customer>{//只能操作某一个表的DAO
}
public class Student {
}
public class StudentDAO extends DAO<Student> {//只能操作某一个表的DAO
}
@Test
public void test1(){
CustomerDAO dao1 = new CustomerDAO();
dao1.add(new Customer());
List<Customer> list = dao1.getForList(10);//查询多条记录
StudentDAO dao2 = new StudentDAO();
Student student = dao2.getIndex(1);//查询一条记录
}
🚤 泛型在继承上的体现
虽然类A是类B的父类,但是G 和G二者不具备子父类关系,二者是并列关系。
@Test public void test1(){ // 类层面的展示 Object obj = null; String str = null; obj = str; // 子类赋给父类的引用 多态 // 数组层面 Object[] arr1 = null; String[] arr2 = null; arr1 = arr2; } @Test public void test1(){ //此时的list1和list2的类型不具有子父类关系 List<Object> list1 = null; List<String> list2 = null; //编译不通过 list1 = list2; // 错误 // 类似于 错误 Date date = new Date(); String str = null; str = date; // 错误 /* 反证法: 假设list1 = list2; list1.add(123);导致混入非String的数据。出错。 所以是错误的 */ }
补充:类A是类B的父类,A
是 B 的父类 @Test public void test2(){ AbstractList<String> list1 = null; List<String> list2 = null; // List interface(接口) ArrayList<String> list3 = null; // 继承 AbstractList list1 = list3; list2 = list3; List<String> list4 = new ArrayList<>(); }
🚗 通配符的使用
通配符:?
- 类A是类B的父类,G和G是没有关系的,二者共同的父类是:G<?>
@Test
public void test3(){
List<Object> list1 = null;
List<String> list2 = null;
List<?> list = null; // 相当于 List<?> 作为 List<Object>、List<String> 的通用父类
list = list1;
list = list2;
//编译通过
print(list1);
print(list2);
}
public void print(List<?> list){
Iterator<?> iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
}
使用通配符结构时
添加(写入):对于List<?>就不能向其内部添加数据,只能添加null(无意义)
获取(读取):允许读取数据,读取的数据类型为Object。
@Test
public void test3(){
List<String> list3 = new ArrayList<>();
list3.add("AA");
list3.add("BB");
list3.add("CC");
List<?> list = null;
list = list3;
//添加(写入):对于List<?>就不能向其内部添加数据。
//list.add(capture of ? e);
// list.add("DD"); 错误
// list.add('?'); 错误
//除了添加null之外。
list.add(null);
//获取(读取):允许读取数据,读取的数据类型为Object。
Object o = list.get(0);
System.out.println(o); // AA
}
🚬 有限制条件的通配符的使用
- ? extends A: 理解为小于等于
- G<? extends A> 可以作为G和G的父类,其中B是A的子类
- ? super A: 理解为大于等于
- G<? super A> 可以作为G和G的父类,其中B是A的父类
@Test
public void test4(){
List<? extends Person> list1 = null;
List<? super Person> list2 = null;
List<Student> list3 = new ArrayList<Student>();
List<Person> list4 = new ArrayList<Person>();
List<Object> list5 = new ArrayList<Object>();
list1 = list3;
list1 = list4;
// list1 = list5;
// list2 = list3;
list2 = list4;
list2 = list5;
System.out.println("---------------------");
//读取数据:
list1 = list3;
Person p = list1.get(0);
//编译不通过
//Student s = list1.get(0);
list2 = list4;
Object obj = list2.get(0);
编译不通过
// Person obj = list2.get(0);
//写入数据:
//编译不通过
// list1.add(new Student()); 子类可以赋给父类 父类不可以赋给子类
// list1.add(new Person());
// list1.add(new Object());
//编译通过
list2.add(new Person()); // Person 和 Person的子类能存放 多态
list2.add(new Student());
}