杭州企业网站定制,个人开公司需要什么条件,网络技术服务有限公司,北京vi设计公司价格学习目标
● 掌握在集合中正确使用泛型 ● 了解泛型类、泛型接口、泛型方法 ● 了解泛型上下限 ● 了解基本的使用场景
1.有关泛型
1.1泛型的概念
泛型#xff08;Generics#xff09;是Java中引入的参数化类型机制#xff0c;允许在定义类、接口或方法时使用类型参数Generics是Java中引入的参数化类型机制允许在定义类、接口或方法时使用类型参数如实际类型在使用时才指定。其本质是通过类型参数化增强代码的灵活性和安全性。 ● 我们将要在集合中接触泛型。了解泛型为学习集合做知识准备 ● 泛型在集合中用于类型检查那么为什么集合中 一定要用到泛型 ○ 若没有泛型的使用那么在设计集合类型时只能确定集合用来装对象但是无法确定装什么类型的对象即集合的元素类型未知。在使用时编译器就无法进行更加具体的类型检查存在类型安全问题 ○ 从集合中取出的集合元素对象为了调用该元素对象的非Object类的方法不得不向下转型就存在ClassCastException的风险存在代码繁琐的问题 ● 有了泛型的使用既能保证安全又能简化代码。 ● 因为如果通过了编译那么类型一定是符合要求的因此就避免了类型转换 ● 类型这种语法形式就叫泛型。 ○ 类型代表未知的数据类型我们可以指定为StringStudent等。相当于把某个具体的类型泛化为一般的类型所以称为泛型或者成为参数化数据类型。参数化类型必须是引用数据类型。 ○ 类型 一般使用一个泛型符号表示泛型符号只是一个占位符 先占着位置给引用类型占位置。 ○ 泛型符号名称不要求个数不要求。 在使用的时候当成已知类型来进行使用。一般使用大写字母A-Z表示。 ○ 泛型符号如果不指定 统统都是Object类型 1.2 泛型的分类
泛型符号可以出现在类声明处 、接口声明处、方法定义中。 ● 泛型在类声明处使用一般称为泛型类。 ● 泛型在接口声明处使用一般称为泛型接口。 ● 泛型在方法定义中使用一般称为泛型方法。
1.3泛型的作用
● 类型安全编译时检查类型一致性避免运行时因类型转换导致的ClassCastException ● 泛型核心作用: 实现数据类型的自动转换避免出现强制转换(较少出现类型转换的异常)。 ● 弊端: 泛型只在编译期间有效运行期间泛型擦除底层还是会将每一个参数化类型改为Object
2.泛型类 在类名后声明类型参数用于成员变量或方法中 ● 泛型符号 可以出现在 类声明处 ● 泛型符号 在本类中当成已知类型来进行使用 ● 静态方法中不能出现 类的泛型符号 2.1 创建泛型类
//泛型里面: 里面必须编写参数化数据类型。引用数据类型 默认值null
public class MyClassS, E {//S,E就是2个参数化数据类型。具体什么类型我们是不清楚的要看使用的时候传过来的数据类型。//使用MyClass没有传递S,E的真实的数据类型S,E默认为Object。//S,E是一个数据类型肯定可以作为形参返回值属性的数据类型。
}2.2 使用泛型类
创建泛型类对象不指定参数化类型
private static void method1() {//调用MyClass里面的属性方法。--- 面向对象编程//还会报警告。对于泛型类、接口 建议指定参数化数据类型//1.创建MyClass类对象MyClass myClass1 new MyClass();//使用MyClass时候 没有指定S,E的真实数据类型。ObjectmyClass1.setName(张三);String name myClass1.getName();myClass1.setS(100);int s (int) myClass1.getS();//对s进行类型强制转换---- 会有几率出现ClassCastExceptionmyClass1.setS(hello);String str (String) myClass1.getS();System.out.println(myClass1.demo1(new int[]{1, 2, 4}));
}创建泛型类对象指定参数化类型
private static void method2() {//创建泛型类对象 指定参数化数据类型引用数据类型//MyClassInteger, String myClass1 new MyClassInteger, String();//jdk1.7之后的写法MyClassInteger, String myClass2 new MyClass();//S:Integer//E:StringmyClass2.setName(李四);String name myClass2.getName();myClass2.setS(100);Integer s myClass2.getS();Integer hello myClass2.demo1(hello);
}3.泛型方法 ● 任意一个类/接口中都可以存在泛型方法。 就是在方法上使用修饰方法。里面的参数化类型就可以是任意数据类型。 ● 泛型符号 只出现本方法的声明处 ● 泛型符号的声明 在返回值的前面 3.1 创建泛型方法
参数化类型仅仅作为形参/返回值使用不是泛型方法
//S 参数化数据类型 作为返回值类型使用
public S getS() {return s;
}
//S作为形参数据类型使用。
public void setS(S s) {this.s s;
}
//getS setS不是泛型方法仅仅是参数化数据类型作为形参/返回值。//普通的方法
//1.非静态的
public S demo1(E e) {System.out.println(demo1............e: e);return s;
}//以上方法仅仅是普通方法 只不过是参数化类型作为形参和返回值使用而已。
//具体形参和返回值是什么类型要看创建对象时指定的数据类型因为这些属性/方法称为实例变量/方法必须对象访问。存在类中的泛型方法
//泛型里面: 里面必须编写参数化数据类型。引用数据类型 默认值null
public class MyClassS, E {//普通的方法//1.非静态的public S demo1(E e) {System.out.println(demo1............e: e);return s;}//2.静态的方法----类名.静态//静态方法里面使用参数化数据类型 必须将这个方法标识为泛型方法public static A,Z void staticMethod(A s1) {System.out.println(s1: s1);}//在任意一个类中 静态方法里面使用了参数类型 这个方法一定是泛型方法//普通的功能方法: 也可以是一个泛型方法public B void demo2(B b){System.out.println(b:b);}
}存在接口中的泛型方法
public interface MyInterfaceK, S {default T void demo1(T t) {System.out.println(t: t);}static E int demo2(E e) {return 100;}
}3.2 使用泛型方法
private static void method3() {//调用staticMethod方法/*MyClassString,String myClass new MyClass();myClass.staticMethod(100.0);*/MyClass.staticMethod(hello);MyClassString,String myClass new MyClass();myClass.demo2(100);
}
private static void method3() {System.out.println(MyInterface.demo2(hello));
}4.泛型接口 接口定义时声明类型参数实现类需指定具体类型或保留泛型 ● 泛型符号 可以出现在 接口声明处 ● 在本接口中当成 已知类型来使用 4.1 创建泛型接口
public interface MyInterfaceK, S {//封装行为//在接口中 定义方法的时候 可以让参数化类型作为形参/返回值使用S method1();void method2(K k);//接口中可以有泛型方法 一般都是静态的//自己很少编写public static A void aa(A a) {}public default B void bb(B b) {}
}public interface GenericInterfaceA, B, C {void methodA(A a);void methodB(B b);void methodC(C c);
}4.2 使用泛型接口
//封装/设计: 一个类实现类泛型接口 这个类一般也是一个泛型类。
public class MyInterfaceImplK,S implements MyInterfaceK,S{Overridepublic S method1() {return null;}Overridepublic void method2(K k) {}
}class Test{public static void main(String[] args) {MyInterfaceInteger,String myInterface new MyInterfaceImpl();}
}//一般在设计中 我们很少这样写
/*** 实现类取实现泛型接口 直接固定类型*/
public class InterfaceImpl1 implements GenericInterfaceString, Integer, Double {Overridepublic void methodA(String s) {}Overridepublic void methodB(Integer integer) {}Overridepublic void methodC(Double aDouble) {}
}/*** 实现类 也带上泛型符号* param A* param B* param C*/
public class InterfaceImpl3A, B, C implements GenericInterfaceA, B, C {private A a;Overridepublic void methodA(A a) {}Overridepublic void methodB(B b) {}Overridepublic void methodC(C c) {}
}5.泛型上下限
通配符与上下界
通配符?表示未知类型用于接受任意泛型类型
public void printList(List? list) { /* 可处理ListString、ListInteger等 */ }上界? extends T限定类型为T或其子类用于读取操作
List? extends Number numbers new ArrayListDouble(); // 允许Double
Number num numbers.get(0); // 安全读取下界? super T限定类型为T或其父类用于写入操作
List? super Integer list new ArrayListNumber();
list.add(123); // 允许写入Integer5.1 问题
创建父类Animal
public class Animal {public void eat() {}
}创建子类 Dog 重写 eat()方法
public class Dog extends Animal {Overridepublic void eat() {System.out.println(狗喜欢吃骨头);}
}创建饲养员类
public class Feeder {public void feed(ListAnimal animals) {for (Animal animal : animals) {animal.eat();}}
}测试饲养员喂食不同小动物
public static void main(String[] args) {Feeder feeder new Feeder();ListAnimal animals new ArrayList();animals.add(new Dog());animals.add(new Cat());ListDog dogList new ArrayList();dogList.add(new Dog());feeder.feed(animals);//编译报错dogList不能传入 feeder.feed(dogList);}5.2 原因 ● 泛型类型的指定上和多态并不相同它要求两边类型必须一致 才能使用因此如何解决上述问题因为在实际业务开发中子类集合也应该是可以传入的此时就需要使用泛型上限进行解决 ● ? 通配符 代表任意类型 ○ 完整形式为类名 或接口名此时?代表上限类型本身或者上限的子类即?代表 5.3 解决
/*** 饲养员类*/
public class Feeder {/*** param animals 泛型的上限* ? 通配符*/public void feed(List? extends Animal animals) {for (Animal animal : animals) {animal.eat();}}/** * 指定了下限 下限就到Animal* 上不要求 所有Animal父类型都可以传*/public void method1(List? super Animal animals) {for (Object animal : animals) {
// animal.eat();}}
}5.4 测试
public static void main(String[] args) {Feeder feeder new Feeder();ListAnimal animals new ArrayList();animals.add(new Dog());animals.add(new Cat());ListDog dogList new ArrayList();dogList.add(new Dog());ListObject objectList new ArrayList();// 泛型上限feeder.feed(dogList);feeder.feed(animals);// 泛型下限feeder.method1(animals);feeder.method1(objectList);}6.泛型擦除
public static void main(String[] args) {ListInteger list new ArrayList(10);list.add(100);list.add(200);//我就是想存一个“hello”到list集合中//编译的class文件中 不存在ListInteger 只有ListObject//泛型在运行期间会被擦除 还是Object类型try {Method addMethod list.getClass().getMethod(add, Object.class);System.out.println(addMethod.invoke(list,hello));} catch (Exception e) {e.printStackTrace();}System.out.println(list);}7.使用场景
泛型类以及泛型接口的出现一般都是满足项目的整体设计。
7.1 泛型类
● 满足与整体的项目功能设计。通用的操作。 ● 需求: 模拟前端请求触发一个按钮的功能。后端就要返回固定格式数据
成功的数据statusmsgdata失败的数据:statusmsg满足所有的模块数据封装。 1.普通类编写
创建MyResult类
Setter
Getter
public class MyResult {private int status;private String msg;private Object data;//查询成功的数据 数据类型不定的public MyResult(int status, String msg, Object data) {this.status status;this.msg msg;this.data data;}public MyResult(int status, String msg) {this.status status;this.msg msg;}
}测试不同模块功能
private static MyResult testFindOneProduct() {ProductDao productDao new ProductDaoImpl();Product product productDao.findOne(1L);if (product null) {return new MyResult(StatusEnum.ERROR.getStatus(), StatusEnum.ERROR.getMsg());}//状态码 msg productreturn new MyResult(StatusEnum.SUCCESS.getStatus(), StatusEnum.SUCCESS.getMsg(), product);
}private static MyResult testFindAllUser() {//模拟测试查询所有用户SysUserDao sysUserDao new SysUserDaoImpl();SysUser[] users sysUserDao.findAll();if (users null || users.length 0) {//查询失败 状态码 msgreturn new MyResult(StatusEnum.ERROR.getStatus(), StatusEnum.ERROR.getMsg());}//查询成功//状态码 msg 查询所有成功的数据 usersreturn new MyResult(StatusEnum.SUCCESS.getStatus(), StatusEnum.SUCCESS.getMsg(), users);
}private static MyResult testFindOneUser() {//模拟测试查询单个用户SysUserDao sysUserDao new SysUserDaoImpl();SysUser sysUser sysUserDao.findOne(1);if (sysUser null) {//查询失败 状态码 msgreturn new MyResult(StatusEnum.ERROR.getStatus(), StatusEnum.ERROR.getMsg());}//查询成功//状态码 msg 查询成功的数据 sysUserreturn new MyResult(StatusEnum.SUCCESS.getStatus(), StatusEnum.SUCCESS.getMsg(), sy测试
public static void main(String[] args) {//前端触发了对用户模块的增删改查//成功/失败MyResult result test2();int status result.getStatus();String msg result.getMsg();Object data result.getData();//查询单个用户对象System.out.println(status);System.out.println(msg);if(status200){SysUser sysUser (SysUser) data;System.out.println(sysUser.getId());System.out.println(sysUser.getName());}System.out.println(data);System.out.println(----------------------------------);MyResult myResult test4();int status1 myResult.getStatus();if(status1200){Object data1 myResult.getData();Product product (Product) data1;}}以上代码封装数据完全ok 弊端 每一次获得data 都要向下转型 会有几率出现类型转换的异常 所以getData的时候 自动的转换成想要的数据类型想到使用 泛型 2.泛型类编写
创建MyResult类
//T: 满足查询成功之后的数据的封装
//封装成功之后的任意类型的封装。
Setter
Getter
public class ReturnResultT {private int status;private String msg;private T data;private ReturnResult(int status, String msg, T data) {this.status status;this.msg msg;this.data data;}private ReturnResult(int status, String msg) {this.status status;this.msg msg;}public static T ReturnResultT success(T data){return new ReturnResult(StatusEnum.SUCCESS.getStatus(),StatusEnum.SUCCESS.getMsg(),data);}public static T ReturnResultT error(){return new ReturnResult(StatusEnum.ERROR.getStatus(),StatusEnum.ERROR.getMsg());}}测试模块功能
public static ReturnResultProduct testFindOneProduct(){ProductDao productDao new ProductDaoImpl();Product product productDao.findOne(1L);if(productnull){return ReturnResult.error();}return ReturnResult.success(product);}//测试查询单个用户public static ReturnResultSysUser testFindOneUser() {SysUserDao sysUserDao new SysUserDaoImpl();SysUser sysUser sysUserDao.findOne(1);if (sysUser null) {return ReturnResult.error();}return ReturnResult.success(sysUser);}7.2 泛型接口
//开发XXXX管理系统:
//1.系统用户模块---- 增加/删除/修改/查询用户 与角色/权限相关的一些行为
//2.订单模块----
//3.商品模块----
//......
//提高程序的扩展性。多态---- 继承类与类 实现 类与接口//有3个实体类封装每个对象具备的信息
//有3个接口封装每个模块里面行为对子接口的抽象: 封装模块里面共有的行为。 //E就是实体类型 T:id的数据类型
public interface BaseDaoE,T {//封装的很多模块具备的一些行为void insert(E entity);void delete(T id);void update(E entity);E findOne(T id);E[] findAll();//还没讲解集合 先使用数组编写
}对共有的行为的实现进行 封装。
public abstract class BaseDaoImplE,T implements BaseDaoE,T {Overridepublic void insert(E entity) {}Overridepublic void delete(T id) {}Overridepublic void update(E entity) {}Overridepublic E findOne(T id) {return null;}Overridepublic E[] findAll() {return null;}
}具体子模块的编写
public interface SysUserDao extends BaseDaoSysUser,Integer {//编写用户模块特有的行为void userLogout();}
public class SysUserDaoImpl extends BaseDaoImplSysUser,Integer implements SysUserDao {//编写用户模块特有行为的实现
}
public interface ProductDao extends BaseDaoProduct,Long {//维护每个模块独有的行为
}public class ProductDaoImpl extends BaseDaoImplProduct,Long implements ProductDao {}