泛型的一些问题
1 可变参数
可变参数的基本格式:
public [static] [final] 返回值 ⽅方法名称([参数类型 参数名称][参数类型 … 参数名称])
{}
这个参数上使用的“…”实际上表示一个数组的结构。
注意点:如果要传递多类参数,可变参数⼀一定放在最后,并且只能设置⼀一个可变参数
package com.guthub.changhyh;
public class TestVarArgs {
// //任意整数求和
// public static int sum(int[] data){
// int sum = 0;
// for (int i = 0; i < data.length; i++) {
// sum += data[i];
// }
// return sum;
// }
public static int sum(String msg, int... data) {
int sum = 0;
for (int i = 0; i < data.length; i++) {
sum += data[i];
}
return sum;
}
public static void main(String[] args) {
System.out.println(sum("hello"));
System.out.println(sum("hello",1,2));
System.out.println(sum("hello",new int[]{1,2,3}));
}
}
2 foreach循环
for(数据类型 临时变量 : 数组(集合)) {
// 循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量
}
for循环⾥⾯⽆须使⽤索引来取数据
package com.guthub.changhyh;
public class TestForeach {
public static void main(String[] args) {
int[]data=new int []{1,2,3,4,5};
int sum = 0;
int index = 0;
//aData 是临时变量
for (int aData : data) {
sum += aData;
System.out.println("index="+index+"value="+aData);
index++;
}
System.out.println("sum"+sum);
}
}
3、静态导⼊(了解)
定义一个MyMath类
package com.guthub.changhyh.until;
public class MyMath {
public static int sum(int a, int b){
return a+b;
}
public static int sub(int a, int b){
return a-b;
}
public static int div(int a, int b){
if (b==0){
throw new IllegalArgumentException("b 作为除数不能为0");
}
return a / b;
}
}
主方法
package com.guthub.changhyh;
import static com.guthub.changhyh.until.MyMath.*;
public class TestMyMath {
public static void main(String[] args) {
System.out.println(sum(1,2));
System.out.println(sub(10,2));
System.out.println(div(2,1));
System.out.println(div(2,0));
}
}
import static com.guthub.changhyh.until.MyMath.*;这就是静态导入
泛型
首先看一段代码
package com.guthub.changhyh.generic;
public class Point {
public Object getX() {
return x;
}
public Object getY() {
return y;
}
public void setX(Object x) {
this.x = x;
}
public void setY(Object y) {
this.y = y;
}
private Object x;
private Object y;
@Override
public String toString() {
return "point{" +
"x=" + x +
", y=" + y +
'}';
}
}
package com.guthub.changhyh.generic;
public class TestPoint {
public static void main(String[] args) {
{
Point intPoint = new Point();
intPoint.setX(10);//int
intPoint.setY(20);
int x = (int) intPoint.getX();
int y = (int) intPoint.getY();
System.out.println("Point(x,y)=(" + x + "," + y + ")");
}
{
//设置数据
Point intPoint1 = new Point();
intPoint1.setX(10.2);
intPoint1.setY("北纬30度");
//取出数据
String x = (String) intPoint1.getX();
String y = (String) intPoint1.getY();
System.out.println("(" +x+","+y + ")");
}
}
这里的ClassCastException 指的是两个没有关系的对象进行强转出现的异常。
所以 :向下转型是不安全的操作,会带来隐患。
需要处理这个异常就需要泛型的概念。
泛型 指的就是在类定义的时候并不会设置类中的属性或方法中的参数的具体类型,而是在类使⽤用时再进行定义。
泛型类的基本语法:
class MyClass<T> {
T value1;
}
尖括号 <> 中的 T 被称作是 类型参数,⽤于指代任何类型。实际上这个 T 你可以任意写,但出于规范的目的,Java 还是建议我们⽤用单个大写字母来代表类型参数。常⻅的如:
1、T 代表⼀般的任何类。
2、E 代表 Element 的意思,或者 Exception 异常的意思。
3、K 代表 Key 的意思
4、V 代表 Value 的意思,通常与 K ⼀起配合使⽤。
5、S 代表 Subtype 的意思。
如果⼀个类被 < T > 的形式定义,那么它就被称为是泛型类。
代码::使⽤用泛型类
MyClass<String> myClass1 = new MyClass<String>();
MyClass<Integer> myClass2 = new MyClass<Integer>();
注意:泛型只能接受类,所有的基本数据类型必须使用包装类!
package com.guthub.changhyh.generic;
public class Point1 <T>{
public Object getX() {
return x;
}
public Object getY() {
return y;
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
@Override
public String toString() {
return "Point1{" +
"x=" + x +
", y=" + y +
'}';
}
private T x;
private T y;
}
主方法
package com.guthub.changhyh.generic;
public class TestPoint1 {
public static void main(String[] args) {
Point1<Integer> intPoint1 = new Point1<>();
intPoint1.setX(10);
intPoint1.setY(20);
int x = (Integer) intPoint1.getX();// 避免了向下转型
int y = (Integer) intPoint1.getY();
System.out.println(x + " " + y);
Point1<String> strPoint1 = new Point1<>();
strPoint1.setX("东经120度");
strPoint1.setY("北纬20度");
System.out.println(strPoint1.getX()+ " " +strPoint1.getY());
}
}
泛型方法
泛型⽅法定义:
class MyClass{
public <T> void testMethod(T t) {
System.out.println(t);
}
}
泛型⽅法与泛型类稍有不同的地方是,类型参数也就是尖括号那⼀部分是写在返回值前面的。 < T > 中的T 被称为类型参数,而⽅法中的 T 被称为参数化类型,它不是运⾏行时真正的参数。
使用类型参数做返回值的泛型⽅法:
class MyClass{
public <T> T testMethod(T t) {
return t;
}
}
泛型⽅法与泛型类是共存的
package com.guthub.changhyh.generic;
public class Point3<T> {
private T x;
private T y;
//泛型方法
public <T> void printPoint(T t){
System.out.println(t);
}
public <T ,E> void printPoint(T t,E e){
//处理业务
System.out.println(t);
System.out.println(e);
}
@Override
public String toString() {
return "Point3{" +
"x=" + x +
", y=" + y +
'}';
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
public T getX() {
return x;
}
public T getY() {
return y;
}
}
主方法
package com.guthub.changhyh.generic;
public class TestPoint3 {
public static void main(String[] args) {
Point3 point3 = new Point3();
Point2<Integer, Double> point2 = new Point2<>();
point2.setX(10);
point2.setY(10.2D);
//T --> Point
point3.printPoint(point2);
point3.printPoint("hello world",20);
}
}
泛型方法始终以自己定义的类型参数为准
从主方法中可以看出
泛型类的实际类型参数是 Integer,⽽传递给泛型方法的类型参数是 String,两者不相干。
通配符(重点)
在程序类中追加了泛型的定义后,避免了ClassCastException的问题,但又会产生新的问题:
参数的统一问题。
package com.guthub.changhyh.generic;
public class Message <T>{
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
@Override
public String toString() {
return "Message{" +
"message=" + message +
'}';
}
}
主方法
package com.guthub.changhyh.generic;
public class TestMessage {
//Message泛型类的类型参数的具体类型 String
public static void fun(Message<String>message){
System.out.println(message.getMessage());
}
//fun方法接收的Message对象的类型参数具体类型是任意类型
public static void fun2(Message<?>message){
//message.setMessage(111);
// 此时使⽤用通配符"?"描述的是它可以接收任意类型,
// 但是由于不不确定类型,所以⽆无法修改
System.out.println(message.getMessage());
}
public static void main(String[] args) {
Message<String> message = new Message<>();
message.setMessage("I AM BEST");
fun(message);
Message<Integer> message1 = new Message<>();
message1.setMessage(999);
fun2(message1);
}
}
泛型上限和下限
1、上限
类型 T extends ClassType
方法参数 ?extends ClassType
方法中不能修改内容
2、下限
方法参数 ? super ClassType
可以修改
1 应用到泛型类
2 应用到方法参数上
泛型上限:
? extends 类:设置泛型上限:
package com.github.changehyh.generic;
import com.github.changehyh.inter.Message;
/**
* 泛型上限
* 1、应用到泛型类
* 2. 应用到方法参数上
*/
public class Message1 <T extends Number>{
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
@Override
public String toString() {
return "Message1{" +
"message=" + message +
'}';
}
//泛型上限
public void print (Message1<? extends Integer>message){
System.out.println(message.getMessage());
}
public static void main(String[] args) {
// Message1<Integer> message1 = new Message1<>();
// message1.setMessage(10);
// System.out.println(message1.getMessage());
Message1<Number> message1 = new Message1<>();
message1.setMessage(10); // 10 -> Integer -> Number
System.out.println(message1.getMessage());
// error 错误
// Message1<Boolean> message1 = new Message1<>();
// message1.setMessage(false);
// System.out.println(message1.getMessage());
}
}
泛型下限:
? super 类:设置泛型下限:
package com.github.changehyh.generic;
import com.github.changehyh.inter.Message;
public class Message2 <T>{
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
@Override
public String toString() {
return "Message2{" +
"message=" + message +
'}';
}
//泛型下限只能⽤在⽅法参数,可以修改内容。
//表示只能够设置String及其父类Object
public static void print(Message2<? super String>message2){
// message2.setMessage(new Integer(20)); 错误
message2.setMessage("Hello World");
System.out.println(message2.getMessage());
}
public static void main(String[] args) {
Message2<String> message2 = new Message2<>();
message2.setMessage("hello bit");
print(message2);
//错误
// Message2<StringBuffer> message3 = new Message2<>();
// message2.setMessage(new StringBuffer("hello bit"));
// print(message2);
}
}
泛型接口:
泛型除了可以定义在类中,也可以定义在接⼝⾥面
第一个: 泛型接口的子类(实现类)直接明确了类型参数的具体类型
第二个:泛型接口的子类定义成泛型类
//泛型接口
public interface IMessage<T> {
void greeting(T t);
String computer (T t , int count);
public static void main(String[] args) {
//第一个
IMessage<String> iMessage = new QQMessage();
iMessage.greeting("hello world");
//第二个
IMessage<Integer> message = new MyMessage<>();
message.greeting(10);
IMessage<StringBuffer> message1 = new MyMessage<>();
message1.greeting(new StringBuffer("Hello StringBuffer"));
}
}
//第一个: 泛型接口的子类(实现类)直接明确了类型参数的具体类型
class QQMessage implements IMessage<String> {
@Override
public void greeting(String s) {
System.out.println("QQ" + s);
}
@Override
public String computer(String ss, int count) {
return null;
}
}
//第二个:泛型接口的子类定义成泛型类
class MyMessage<T> implements IMessage<T>{
@Override
public void greeting(T t) {
System.out.println(t);
}
@Override
public String computer(T t, int count) {
return null;
}
}
类型擦除:
泛型信息只存在于代码编译阶段,在进⼊ JVM 之与泛型相关的信息会被擦除掉,专业术语叫做类型擦除。通俗地讲,泛型类和普通类在 java 虚拟机内是没有什么特别的地方。
泛型信息是编译阶段的内容 编译时会进行类型擦除,JVM运行时泛型类和普通类没有区别
类型擦除原则:
T 变成Object
T extends ClassType 变成 ClassType
public class MyClass <T>{
private T message;
public T getMessage(){
return message;
}
public void setMessage(T message) {
this.message = message;
}
public static void main(String[] args) {
//1. 泛型类在使用时(运行)和普通类没有区别
//2. 验证 运行时 T 正真类型
MyClass myClass1 = new MyClass();
MyClass <String>myClass2 = new MyClass<>();
MyClass <Integer>myClass3 = new MyClass<>();
//反射
System.out.println(myClass1.getClass());
System.out.println(myClass2.getClass());
System.out.println(myClass3.getClass());
}
}
//在泛型类被类型擦除的时候,之前泛型类中的类型参数部分 如果没有指定上限,如 则会被转译成普通的 Object 类型, 如果指定了上限如 <T extends Number,E extends CharSequence> 则类型参数就被替换成类型上限。
package com.github.changehyh.generic;
import java.lang.reflect.Field;
public class MyClass2 <T extends Number,E extends CharSequence>{
private T message;
private E element;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public E getElement() {
return element;
}
public void setElement(E element) {
this.element = element;
}
public static void main(String[] args) {
MyClass2<Integer,String> myClass2 = new MyClass2<>();
///MyClass2 在运行时 message element属性具体类型
Field[] fields = myClass2.getClass().getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName()+ " " + field.getType());
}
}
}
上一篇: JAVA 泛型T V 等一些方法
下一篇: 使用反射来获取泛型信息