目录
引入
一个学生的成绩有三种情况,应如何处理?
1、整数
2、小数
3、字符串
代码:
student.java
public class Student {
private Object javase;
private Object oracle;
public Student(Object javase, Object oracle) {
super();
this.javase = javase;
this.oracle = oracle;
}
public Object getJavase() {
return javase;
}
public void setJavase(Object javase) {
this.javase = javase;
}
public Object getOracle() {
return oracle;
}
public void setOracle(Object oracle) {
this.oracle = oracle;
}
}
app.java
/**
* 获取值:
* 1.强制类型转换
* 2.手动类型检查:避免转换错误:java.lang.ClassCastException
* @author qiao39gs
*
*/
public class App {
public static void main(String[] args) {
Object obj = 80;
//int score = (int)obj; //jdk1.7以后:Object—Integer—自动拆箱
int score = (Integer) obj; //jdk1.6及以前版本
System.out.println(score);
//存入整数:int—Integer—Object
Student stu = new Student(80,90);
int javaseScore = (Integer) stu.getJavase();
String oracleScore = null;
if(stu.getOracle() instanceof String){
oracleScore = (String) stu.getOracle();
}
System.out.println("分数为:"+javaseScore+","+oracleScore);
}
}
不能将oracle的成绩转换为String类型
概述
- 概念:泛型就是参数化类型,使用广泛的类型。
- 起因:数据类型不明确:
- 装入数据的类型都被当作Object对待,从而“丢失”自己的实际类型。
- 获取数据时往往需要转型,效率低,容易产生错误
- 作用:
- 安全:在编译的时候检查类型安全
- 省心:所有的强制转换都是自动和隐式的,提高代码的重用率
泛型类
- 格式:<>
class类名<字母列表>{
修饰符 字母 属性 ;
修饰符 构造器(字母){
}
修饰符 返回类型 方法(字母){
}
不能使用在静态属性、静态方法上 - 使用:指定具体类型
1.编译时会进行类型检查;
2.获取数据时不需要强制类型转换。
泛型使用时不能指定基本类型。 - 泛型常见字母
T Type表示类型
K V 分别代表键值中的Key Value
E 代表 Element
?表示不确定的类型
eg:
/**
* 泛型类:声明时使用泛型
* 使用时确定类型
* @author qiao39gs
*
* @param <T>
*/
public class Student<T1,T2> {
private T1 javaScore;
private T2 oracleScore;
//private static T1 test; //不能使用静态属性|静态方法上
public T1 getJavaScore() {
return javaScore;
}
public void setJavaScore(T1 javaScore) {
this.javaScore = javaScore;
}
public T2 getOracleScore() {
return oracleScore;
}
public void setOracleScore(T2 oracleScore) {
this.oracleScore = oracleScore;
}
public static void main(String[] args) {
//使用时指定类型
Student<String,Integer> stu = new Student<String,Integer>();
//1.安全:类型检查
stu.setJavaScore("优秀");
//2.省心:类型转换
stu.setOracleScore(93);
int it = stu.getOracleScore(); //自动拆箱
}
}
泛型接口:定义类时使用泛型
- 格式:<>
interface 接口名 <字母列表>{
修饰符 返回类型 方法(字母);
} - 因为不能使用在静态属性上,更不能用在全局常量上
eg:
/**
* 接口中泛型字母只能使用在方法中,不能使用在全局常量中
* @author qiao39gs
*
* @param <T>
*/
public interface Comparator<T> {
void compare(T t);
}
泛型方法
- 定义使用:<字母>
修饰符 <字母> 返回类型 方法名(字母){
}
要定义泛型方法,只需将于泛型参数列表置返回值前 - 注意:泛型还可以定义在方法中,是否拥有泛型方法,与其所在的类是否泛型没有关系
eg:
/**
* 泛型方法<> 返回类型签名
* 只能访问对象的信息,不能修改信息
* @author qiao39gs
*
*/
public class TestMethod {
public static void main(String[] args) {
test("a"); //T—String
}
//泛型方法
public static<T> void test(T a){
System.out.println(a);
}
}
泛型子类
- 子类与父类|接口一样使用泛型
- 子类指定具体的类型
- 子类与父类|接口同时擦除类型
- 子类泛型,父类接口 擦除
- 错误:不能子类擦除,父类|接口泛型
擦除统一使用 Object对待
eg:
/**
* 父类为泛型类
* 1.属性
* 2.方法
*
* 要么同时擦除,要么子类大于等于父类的类型
* 不能子类擦除,父类泛型
* 1.属性类型
* 父类中,随子类而定
* 子类中,随子类而定
* 2.方法重写:
* 随父类而定
*
*
* @author qiao39gs
*
* @param <T>
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t);
}
/**
* 子类声明时指定具体类型
* 属性类型为具体类型
* 方法同理
*/
class Child1 extends Father<String,Integer>{
String t2;
@Override
public void test(String t){
}
}
/**
* 子类为泛型类,类型在使用时确定
* @param <T1>
* @param <T>
*/
class Child2<T1,T> extends Father<T,T1>{
T t2;
@Override
public void test(T t){
}
}
/**
* 子类为泛型,父类不指定类型,泛型的擦除,使用Object替换
* @param <T1>
* @param <T>
*/
class Child3<T1,T2> extends Father{
@Override
public void test(Object t){
}
}
/**
* 子类与父类同时擦除
*/
class Child4 extends Father{
String name;
@Override
public void test(Object t) {
// TODO Auto-generated method stub
}
}
/**
* 错误:子类擦除,父类使用泛型
class Child5 extends Father<T,T1>{
String name;
@Override
public void test(T t) {
// TODO Auto-generated method stub
}
}
*/
泛型擦除
- 擦除:
- 在使用时没有指定具体的类型
- 子类继承时没有指定类型
- 处理:
- 擦除后不类型检查
- 一旦擦除之后按Object接收
- 依然存在编译警告,加上 Object可以去除,但是有些画蛇添足
eg:
/**
* 泛型接口:与继承同理
* 重写方法随父类而定
* @author qiao39gs
*
* @param <T>
*/
public interface Comparable<T> {
void compare(T t);
}
//声明子类指定具体类型
class Comp implements Comparable<Integer>{
@Override
public void compare(Integer t) {
// TODO Auto-generated method stub
}
}
//擦除
class Comp1 implements Comparable{
@Override
public void compare(Object t) {
// TODO Auto-generated method stub
}
}
//父类擦除,子类泛型
class Comp2<T> implements Comparable{
@Override
public void compare(Object t) {
// TODO Auto-generated method stub
}
}
//子类泛型>=父类泛型
class Comp3<T> implements Comparable<T>{
@Override
public void compare(T t) {
// TODO Auto-generated method stub
}
}
//父类泛型,子类擦除 错误
eg2:
/**
* 泛型的擦除
* 1.继承|声明不指定类型
* 2.使用时不指定类型
* 统一Object对待
* 1.编译器警告(Student is a raw type. References to generic type Student<T> should be parameterized)
* 消除警告:加<Object>
* 2.不完全等同于Object,编译不会类型检查
* @author qiao39gs
*
* @param <T>
*/
public class Student<T> {
private T javaScore;
private T oracleScore;
//private static T1 test; //不能使用静态属性|静态方法上
public T getJavaScore() {
return javaScore;
}
public void setJavaScore(T javaScore) {
this.javaScore = javaScore;
}
public T getOracleScore() {
return oracleScore;
}
public void setOracleScore(T oracleScore) {
this.oracleScore = oracleScore;
}
public static void main(String[] args) {
Student stu = new Student();
//消除警告使用Object
Student<Object> stu1 = new Student<Object>();
stu1.setJavaScore("A"); //以Object对待
test(stu); //stu相当于 Object但是不完全等同 Object
//擦除,不会类型检查
//test(stu1);
test1(stu);
test1(stu1);
}
public static void test(Student<Integer> a){
}
public static void test1(Student<?> a){
}
}
泛型没有多态
- 回顾类与接口存在多态
- 泛型没有多态
直接使用:A< Object> a = new A< String>(); 错误
方法形参与返回类型也不存在泛型多态 - 不能使用instanceof判断是否为泛型实例
a instanceof A<String>
多态的两种形式eg:
Fruit.java:
public class Fruit {
}
class Apple extends Fruit{
}
FruitApp.java
public class FruitApp {
public static void main(String[] args) {
Fruit f = new Apple();
test(new Apple());
}
//形参使用多态
public static void test(Fruit f){
}
//返回类型使用多态
public static Fruit test2(){
return new Apple();
}
}
泛型不能使用多态:
A.java
public class A<T> {
}
App.java
public class App {
public static void main(String[] args) {
//A<Fruit> f = new A<Apple>(); 报错:Type mismatch: cannot convert from A<Apple> to A<Fruit>
A<Fruit> f = new A<Fruit>();
//test(new A<Apple>()); 报错:The method test(A<Fruit>) in the type App is not applicable for the arguments (A<Apple>)
}
//形参使用多态
public static void test(A<Fruit> f){
}
//返回类型使用多态
public static A<Fruit> test2(){
//return (A<Fruit>) (new A<Apple>()); 报错:Cannot cast from A<Apple> to A<Fruit>
return null;
}
}
通配符
? extends super
- 可以用在声明类型及声明方法参数上,不能用在声明类上
- ?可以接受泛型的任意类型,只能接收和输出,不能修改
方法声明时参数无法正确知道具体的类型,因此不能修改 - ? extends 泛型上限 <=
- ? super 泛型下限 >=
/**
* ?类型不定,使用时确定类型
* ?的使用:声明类型|声明方法上,不能声明类或使用时
* ? extends <= 泛型上限 指定类型 子类或自身
* ? super >= 泛型下限 指定类型为自身或父类
* @author qiao39gs
*
*/
public class Student<T> {
T score;
public static void main(String[] args) {
Student<?> stu = new Student<String>();
test(new Student<Integer>());
test2(new Student<Apple>());
//test3(new Student<Apple>()); //泛型没有多态
//test4(new Student<Apple>()); //<
stu = new Student<Fruit>();
//test4(stu); //使用时确定类型
test4(new Student<Object>());
test4(new Student<Fruit>());
}
public static void test(Student<?> stu){
}
public static void test3(Student<Fruit> stu){
}
// <=
public static void test2(Student<? extends Fruit> stu){
}
// >=
public static void test4(Student<? super Fruit> stu){
}
}
泛型嵌套
- 声明:嵌套使用泛型
A<B<C>> a = new A<B<C>>(); - 使用:从外到内,一层层拆分
稍微复杂一些,与调用没有任何的关系,只确定了类型
public class Nest <T> {
T stu;
public static void main(String[] args) {
//泛型的嵌套
Nest<Student<String>> room = new Nest<Student<String>>();
//从外到内拆分
room.stu = new Student<String>();
Student<String> stu = room.stu;
String score = stu.score;
System.out.println(score);
}
}
泛型与数组
- 没有泛型数组,不能创建泛型数组
- 可以只有声明,可以使用?
- A<String>[] a1 = null;
- A<?>[] a2 = new A<?>[10];
public class Array {
public static void main(String[] args) {
Student<?>[] arr2 = new Student[10];
MyArrayList<String> strList = new MyArrayList<String>();
strList.add(0,"aa");
String elem = strList.getElem(0);
System.out.println(elem);
}
}
class MyArrayList<E>{
//E[] cap = new E[10]; 没有泛型数组
Object[] cap = new Object[10];
public void add(int idx,E e){
cap[idx] = e;
}
public E[] getAll(){
return (E[]) cap;
}
public E getElem(int idx){
return (E) cap[idx];
}
}
JDK7泛型改进
- jdk7改进:声明时指定泛型即可,创建对象不用再次编写类型
- 如 A<String> a = new A<>0;
public class Test7 {
public static void main(String[] args) {
List<String> arrList = new ArrayList<String>();
List<String> arrList2 = new ArrayList<>();
}
}