泛型
-----------先写一个ObjectStack类实现栈的操作-----------
class ObjectStack{
private Object[] elem;
private int top;
public ObjectStack(){
this(10);
}
public ObjectStack(int size){
this.elem = new Object[size];
this.top = 0;
}
public void push(Object value){
this.elem[this.top++] = value;
}
public void pop(){
--this.top;
}
public Object getTop(){
return this.elem[this.top-1] ;
}
}
public class ObjectStackDemo {
public static void main(String[] args) {
ObjectStack objectStack = new ObjectStack();
objectStack.push(10);
objectStack.push(66.6);
objectStack.push("showLo");
//String str = (String) objectStack.getTop();
//这里必须强转,否则会报错
//对多数据来说很麻烦
//System.out.println(str);
}
}
虽然ObjectStack对元素数据类型没有限制, 放任何类型的数据进去都会编译通过,但是都默认为Object类型,所以当我们得到栈顶元素时,返回的是Object类,获取该元素时需要进行强制转换。。。。就很麻烦la。。。。。
所以…我们有了泛型~~
emmmmmm…什么是泛型呢???
就是----------适用于许多许多的类型。
所以上面的例子用泛型来写就很nice了!!!
class GenericStack<T> {
private T[] elem;
private int top;
public GenericStack() {
this(10);
}
public GenericStack(int size) {
//this.elem = new T[size]; error
this.elem = (T[]) new Object[size];
this.top = 0;
}
public void push(T value){
this.elem[this.top++] = value;
}
public void pop(){
this.elem[this.top-1] = null;
--this.top;
}
public T getTop(){
return this.elem[this.top-1];
}
}
测试
public class GenericStackDemo {
public static void main(String[] args) {
//想用哪种类型就在创建的时候指定该类型
GenericStack<Integer> genericStack = new GenericStack<Integer>();
genericStack.push(10);
//用指定类型以外的类型则会出现错误
//genericStack.push("ss"); error
//genericStack.push(10.3); error
int data = genericStack.getTop();
GenericStack<Double> genericStack1 = new GenericStack<Double>();
genericStack1.push(40.3);
//GenericStack<Integer>[] genericStack3 = new GenericStack<Integer>(); error
// 不能new泛型类型的对象数组
}
}
泛型概述
- 通过泛型可以定义类型安全的数据结构,而无需使用实际的数据类型
- 泛型类和泛型方法具有可重用性、类型安全性和高效性
- 在泛型类型定义中,必须通过指定尖括号中的类型参数来声明类型。参数类型不是特定的类型,而是类型占位符
class GenericStack<T>
T只是一个类型的占位符,表示GenericStack是一个泛型类
- 在创建泛型类型的实例对象时,必须指定尖括号的类型,可以是编译器识别的任何类型(!!!不能为简单类型)
GenericStack<Integer> genericStack = new GenericStack<Integer>();
GenericStack<Animal> genericStack2 = new GenericStack<Animal>();
泛型的意义
- 可以对类型进行自动检查(并不是替换)在编译期间进行检查
- 自动对类型进行转换
泛型是怎么编译的呢???
是用了类型的擦除机制,通过向上擦除===》Object类
(在编译器的编译期间,把泛型全部擦除为Object类型)
public static void main(String[] args) {
GenericStack<Integer> genericStack = new GenericStack<Integer>();
GenericStack<String> genericStack1 = new GenericStack<String>();
System.out.println(genericStack);
System.out.println(genericStack1);
System.out.println(int.class);
System.out.println(String.class);
System.out.println(GenericStack.class);
}
写一个通用的算法,找到数组当中的最大值
class GenericAlg<T extends Comparable<T>>{
public T findMaxVal(T[] array) {
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
测试代码
public class Test2 {
public static void main(String[] args) {
Integer[] array ={1,2,3,4,5};
GenericAlg<Integer> genericAlg = new GenericAlg<Integer>();
System.out.println(genericAlg.findMaxVal(array));
Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
GenericAlg<Double> genericAlg1 = new GenericAlg<Double>();
System.out.println(genericAlg1.findMaxVal(array1));
}
}
//5
//6.6
泛型方法
//泛型的上界-----》T extends Comparable<T>
//泛型没有下界
class GenericAlg2{
public static<T extends Comparable<T>> T findMaxValu(T[] array){
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
public class Test2 {
public static void main(String[] args) {
Integer[] array ={1,2,3,4,5};
Double[] array1 = {3.6,4.8,5.9,6.6,0.9};
//T会通过实参的类型推演出泛型类型
System.out.println(GenericAlg2.findMaxValu(array));
System.out.println(GenericAlg2.findMaxValu(array1));
System.out.println(GenericAlg2.<Integer>findMaxValu(array)); //也可在前面指明其类型
}
//5
//6.6
内存泄漏
// An highlighted block
var foo = 'bar';
泛型的坑
- 不能new泛型类型的数组
- eg: new T[];
- 不能new泛型类型的对象
- eg: T obj = new T();
- 不能new 泛型类型的对象数组
- eg: Object[] obj = new GenericStack[10];
- 不能用简单类型作为泛型类型的参数
- 一定记得加<泛型类型的参数>,否则就是Object
- 不能 GenericStack genericStack3 = new GenericStack();
- 应该 GenericStack genericStack = new GenericStack();
- 在静态方法中不能使用泛型类型的参数,因为静态方法不依赖对象,如果不依赖对象,就不知道这个T是什么类型,编译时就不能进行类型检查
通配符(?)
通过擦除机制 ------》 Object
写一个通用的算法:打印集合ArrayList内的所有元素
class GenericAlg1{
public static <T> void printList(ArrayList<T> list){
for (T obj : list){
System.out.println(obj + " ");
}
System.out.println();
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
GenericAlg1.printList(arrayList);
}
}
Integer 继承 Number , Number 继承 Object
但是 ArrayList ArrayList ArrayList 三者间不能构成继承关系
class GenericAlg1{
public static void printList(ArrayList<?> list) {
for (Object obj : list) {
System.out.println(obj + " ");
}
System.out.println();
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(10);
arrayList.add(20);
arrayList.add(30);
GenericAlg1.printList(arrayList);
// ArrayList<Object> arrayList1 = new ArrayList<Integer>(); error,不构成继承关系
}
}
通配符的应用
写一个算法找集合当中的最大值
比较时报错,应该怎么办呢???
解决办法如下
class GenericAlg2{
public static <T extends Comparable<T>> T findMaxVal(ArrayList<T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
}
通配符的上下界
可以使用 extends 为通配符限定上界或使用 super 为通配符限定下界
<? extends 基类> //? 限定为指定类或其派生类
<? super 派生类> //? 限定为指定类或其基类
- 通配符的上界主要用来写入
- 通配符的下界主要用来读取
class GenericAlg2{
//通配符的下界:找到是不是有T的基类实现了Comparable接口
public static <T extends Comparable<? super T>> T findMaxVal1(ArrayList<T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
//通配符的上界 ArrayList<? extends T>
public static <T extends Comparable<T>> T findMaxVal(ArrayList<? extends T> list){
T max = list.get(0);
for (int i = 0; i < list.size(); i++) {
if (max.compareTo(list.get(i)) < 0){
max = list.get(i);
}
}
return max;
}
}
class Person implements Comparable<Person>{//不实现接口main函数调用方法时会报错
private String name;
public Person(String name){
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
@Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
}
class Student extends Person{
private int age;
public Student(String name,int age){
super(name);
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"age=" + age +
'}';
}
}
public class GenericDemo {
public static void main(String[] args) {
ArrayList<Person> arrayList = new ArrayList<Person>();
arrayList.add(new Person("ss"));
arrayList.add(new Person("qq"));
System.out.println(GenericAlg2.findMaxVal(arrayList));
ArrayList<Student> arrayList1 = new ArrayList<Student>();
arrayList1.add(new Student("ss",8));
arrayList1.add(new Student("qq",18));
System.out.println(GenericAlg2.findMaxVal(arrayList1));
System.out.println(GenericAlg2.findMaxVal1(arrayList1));
}
}