赞
踩
大O符号(Big O notation):是用于描述函数渐进行为的数学符号
推导大O阶方法
效果:去掉了那些对结果影响不大的项,简洁明了的表示出了执行次数
结果形式:
概念:对一个算法在运行过程中临时占用存储空间大小的量度,在实际上算的是变量的个数
计算方式:求出变量的个数后,用大O渐进表示法表示
在Java中,由于基本数据类型不是继承与Object的,为了在泛型代码中可以支持基本类型,Java中每一个基本数据类型都有一个对应的包装类
对于基本类型来说,包装类中的属性和方法,可以让数据的转换等使用方法更加方便
基本数据类型 | 包装类 |
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
除了 Integer 和 Character ,其余基本类型的包装类都是首字母大写
public static void main1(String[] args) {
int a = 10;
int b = 20;
//自动装箱
Integer i = a;//与Integer i = Integer.valueOf(a);是一样的,JVM会帮着调用一个valueOf方法
Integer iiii = (Integer) b;
显示装箱
int c = 30;
int d = 40;
Integer iii = Integer.valueOf(c);//使用类调用的,说明是被static修饰的
Integer ii = new Integer(d);
}
❤️Integer.valueOf方法介绍
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
public static void main2(String[] args) {
Integer a = 10;
//自动拆箱
int ii = a;
int iii = (int)a;
//显示拆箱
int i = a.intValue(); //用对象调用,说明这是一个类中的方法
float f = a.floatValue();
}
<>里面一定是个引用类型
语法(1)------------>定义一个泛型类
class 泛型类名称<类型形参列表>{
//这里可以使用类型参数
}
语法(2)------------>定义一个继承某个类的泛型类
class 泛型类名称<类型形参列表> extends 继承类(这里可以使用类型参数){
//可以只使用部分类型参数
}
语法(3)------------>定义一个泛型类引用
泛型类<类型实参>变量名;
语法(4)------------>实例化一个泛型类对象
new 泛型类<类型实参>(构造方法实参);
语法(5)------------>裸类型
概念:是一个泛型类但是没有带着类型实参,意味着什么都能放,那取出来还要强转
注意:不要主动去使用裸类型,因为这是为了兼容老版本保留的机制
class MyArray4<T>{ //定义一个泛型类,T这边的效果就是传什么就是什么,T表示的是这是一个占位符,表示当前类是一个泛型类 public Object[] objects = new Object[10]; //最好的写法 //public T[] objects2 = new T[5]; 错误,数组在new的时候,后面一定要跟一个具体的类型 public T[] objects3 = (T[])new Object[5]; //这种可以,但是不好 public Object getPos(int pos){ return objects3[pos]; } } public class Test { public static void main(String[] args) { MyArray<Integer> myArray = new MyArray<>(); //语法3+语法4,Integer表示指定传的是int类型的 MyArray<Integer> myArray1 = new MyArray<Integer>(); //裸类型 //效果和上一行是一样的,实例化对象那边的<>中的包装类型是可以省略的,因为可以根据上下文推导出实例化所需要的类型实参 //数组在new的时候,后面一定要跟一个具体的类型,因为T这种占位符在运行的时候是不知道是什么的 //T[] ts = new T[5]; } }
class MyArray1<T>{ public Object[] objects = new Object[10]; public T getPos(int pos){ return (T)objects[pos]; } public void setPos(int pos, T val){ objects[pos] = val; } } public class Test{ public static void main(String[] args){ MyArray1<Integer> myArray1 = new MyArray1<>(); myArray1.setPos(0, 20); System.out.println(myArray1.getPos(0)); MyArray1<String> myArray2 = new MyArray1<>(); myArray2.setPos(0, "aaa"); System.out.println(myArray2.getPos(0)); } }
泛型的编译中需要遵循一个擦除机制
擦除机制就是在编译的过程当中把所有的T替换成Object这种机制,所以在运行的时候是没有T的,即没有泛型的概念
❤️为什么不能实例化泛型数组
错误示例
class MyArray<T>{ public T[]array = (T[])new Object[10]; public T getPos(int pos){ return this.array[pos]; } public void setVal(int pos, T val){ this.arrar[pos] = val; } public T[] getArray(){ return array; } } public class Main{ public static void main(String[]args){ MyArrar<Integer> myArray1 = new MyArray<Integer>(); Integer[] intgers = myArray1.getArray(); //不知道该用什么接收 } }
会报错,返回的Object数组里面,可能存放的是任何的数据类型,运行的时间直接传给Integer等类型的数组,会被编译器认为不安全
那怕是强转都不行,因为Object类型表示这里面什么类型都可以放,即可能有char、String等类型,全部都转为Integer会不安全
正确解法
class MyArray1<T>{ public Object[] objects = new Object[10]; public T getPos(int pos){ return (T)objects[pos]; } public void setPos(int pos, T val){ objects[pos] = val; } public Object[] getArray(){ return objects; } } public class Test{ public static void main(String[] args){ MyArray1<Integer> myArray1 = new MyArray1<>(); myArray1.setPos(0, 20); System.out.println(myArray1.getPos(0)); MyArray1<String> myArray2 = new MyArray1<>(); myArray2.setPos(0, "aaa"); System.out.println(myArray2.getPos(0)); } }
概念:在定义泛型类时,对传入的类型变量通过类型边界作一定的约束
语法:
class 泛型类名称<类型形参 extends 类型边界>{
}
示例
class MyArray< E extends Number>{
}
E要么是Number的子类,要么就是Number
代码示例 ------------------> 写一个泛型类,求数组中的最大值
<>里面的一定是个引用类型,而引用类型是不可以通过大于和小于进行比较的,因为T在编译的时候会变成Object类,Object类是所有类的父类,本身并没有关联Comparable接口,所以这个泛型类要关联Comparable接口
class Alg<T extends Comparable<T>>{ //擦除为一个实现了这个接口的类型 public T findMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { //引用类型不可以通过 大于和小于进行比较 if(max.compareTo(array[i]) < 0 ) { max = array[i]; } } return max; } } public class Test{ public static void main(String[] args){ Alg<Integer> alg = new Alg<>(); Integer[] array = {1, 5, 2, 7, 19, 4}; Integer max = alg.<Integer>findMax(array); //可以通过array类判断传的是什么类型的数据 System.out.println(max); } }
//这是用静态泛型方法去写 class Alg2 { public static<T extends Comparable<T>> T findMax(T[] array) { T max = array[0]; for (int i = 1; i < array.length; i++) { if(max.compareTo(array[i]) < 0 ) { max = array[i]; } } return max; } } public class Test2 { public static void main(String[] args) { Integer[] array = {1,5,2,7,19,4}; Integer max = Alg2.<Integer>findMax(array);//可以通过array类判断传的是什么类型的数据 System.out.println(max); } }
语法:
方法限定符<类型形参列表> 返回值类型 方法名称(形参列表){
}
示例
public class Util {
//静态的泛型方法 需要在static后用<>声明泛型类型参数
public static <E> void swap(E[] array, int i, int j) {
E t = array[i];
array[i] = array[j];
array[j] = t;
}
}
使用示例-可以类型推导
Integer[] a = { ... };
swap(a, 0, 9);
String[] b = { ... };
swap(b, 0, 9);
使用示例-不使用类型推导
Integer[] a = { ... };
Util.<Integer>swap(a, 0, 9);
String[] b = { ... };
Util.<String>swap(b, 0, 9);
1. 使用场景
概念:? 用于在泛型的使用,即为通配符
使用场景:可以接收所有的泛型类型,但是又不能够让用户随意修改
public class TestDemo {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
}
// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<?> temp){
//temp.setMessage(100); 无法修改!
System.out.println(temp.getMessage());
}
}
2. 通配符上界
class Food { } class Fruit extends Food { } class Apple extends Fruit { } class Banana extends Fruit { } class Message<T> { // 设置泛型 private T message ; public T getMessage() { return message; } public void setMessage(T message) { this.message = message; } } public class TestDemo { public static void main(String[] args) { Message<Apple> message = new Message<>() ; message.setMessage(new Apple()); fun(message); Message<Banana> message2 = new Message<>() ; message2.setMessage(new Banana()); fun(message2); } // 此时使用通配符"?"描述的是它可以接收任意类型 //但是由于不确定类型,所以无法修改.此时无法在fun函数中对temp进行添加元素, //因为temp接收的是Fruit和他的子类,此时存储的元素应该是哪个子类无法确定 //所以添加会报错!但是可以获取元素。 public static void fun(Message<? extends Fruit> temp){ //temp.setMessage(new Banana()); //仍然无法修改! //temp.setMessage(new Apple()); //仍然无法修改! System.out.println(temp.getMessage()); } }
通配符的上界,不能进行写入数据,只能进行读取数据
3. 通配符下界
class Food { } class Fruit extends Food { } class Apple extends Fruit { } class Plate<T> { private T plate ; public T getPlate() { return plate; } public void setPlate(T plate) { this.plate = plate; } } public class TestDemo { public static void main(String[] args) { Plate<Fruit> plate1 = new Plate<>(); plate1.setPlate(new Fruit()); fun(plate1); Plate<Food> plate2 = new Plate<>(); plate2.setPlate(new Food()); fun(plate2); } public static void fun(Plate<? super Fruit> temp){ // 此时可以修改!!添加的是Fruit 或者Fruit的子类 temp.setPlate(new Apple());//这个是Fruit的子类 temp.setPlate(new Fruit());//这个是Fruit的本身 //Fruit fruit = temp.getPlate(); 不能接收,这里无法确定是哪个父类 System.out.println(temp.getPlate());//只能直接输出 } }
通配符的下界,不能进行读取数据,只能写入数据。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。