一、JDK1.5新特性:泛型、枚举、注解
1、可变参数:要求方法可以接收任意个整数并且返回他们的相加结果。
public [static] [final] 返回值 方法名称 ([参数类型 参数名称] [参数类型 … 参数名称]){}
- 这个参数使用的“…”实际表示一个数组的结构。
package 泛型;
public class Test0124_1 {
public static int add(int ... data) {//本身还是一个数组
int result = 0;
for (int i = 0; i < data.length; i++) {
result += data[i];
}
return result;
}
public static void main(String[] args) {
System.out.println(add(1,4,5,6));//随意传递的内容,随意个数
System.out.println(add(new int[]{1, 3, 5}));//可变参数可以接收数组
System.out.println(add(new int[]{1, 3, 5, 7}));
}
}
运行结果:
16
9
16
语法:类型 … 参数名称
一个方法有且仅有一个可变参数,并且放在方法的最后哦一个参数。
可变参数的本质还是数组。
注意:如果要传递多类参数,可变参数一定要放在最后,并且只能设置一个可变参数。
//传递多类参数
public class Test0124_1{
public static void main(String[] args) {
System.out.println(add("hello"));
System.out.println(add("hello", 1, 4, 5, 6));
System.out.println(add("hello", new int[]{1, 2, 3}));
}
public static int add(String msg, int... data) {
int result = 0;
for (int i = 0; i < data.length; i++) {
result += data[i];
}
return result;
}
}
运行结果:
0
16
6
2、foreach用于数组与类集的简单输出
for(数据类型 临时变量:数组/类集){
//循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量
}
public class Test0124_1{
public static void main(String[] args) {
int[] data = new int[]{1,2,3,4,5};
for (int i : data) {//将数组中每个元素赋值给i
System.out.println(i);//这种循环避免了下标的问题
}
}
}
运行结果:
1
2
3
4
5
3、静态导入(了解)
//导入test包中的myMath类
import static test.myMath;//静态导入
4、泛型
(1)泛型类:
泛型指的是在类定义时并不会设置类中的属性或方法中参数的具体类型,而是在类使用时再定义。
语法:
class MyClass<T>{
T value1;
}
在类使用时再定义类中属性的具体类型:
class MyClass<T>{
private T value1;//此时并不定义属性的类型是哪一个
public T getValue1(){
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
}
public class Test0124_1 {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();//现在使用类,所以要指定类型
myClass.setValue1("hello");
System.out.println(myClass.getValue1());
MyClass<Integer> myClass1 = new MyClass<>();
myClass1.setValue1(10);
System.out.println(myClass1.getValue1());
}
}
class MyClass<T,E>{
private T value1;
private E value2;
public T getValue1(){
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
public E getValue2() {
return value2;
}
public void setValue2(E value2) {
this.value2 = value2;
}
}
public class Test0124_1 {
public static void main(String[] args) {
MyClass<Integer,String> myClass = new MyClass<Integer, String>();
myClass.setValue1(11);
myClass.setValue2("SL");
System.out.println(myClass.getValue1());
System.out.println(myClass.getValue2());
}
}
T被称为类型参数,用于指代任何类型。
T:代表一般的类
E:代表Element,常用于泛型类中的属性
K、V:键值对,见Map集合
S:Subtype,子类的意思
泛型只允许接收类,所有基本类型必须使用包装类。
(2)泛型方法
public <T> void MyMethod(T t){
System.out.print(t);
}
- 当泛型类与泛型方法共存时,泛型类中的类型参数与泛型方法中的类型参数没有关系,泛型方法始终以自己定义的类型参数为准。
- 规范:泛型方法的类型参数与泛型类的类型参数不要同名。
class MyClass<T>{
//普通方法
public void method1(T t) {
System.out.println(t);
}
//泛型方法
public <E> void method2(E e) {
System.out.println(e);
}
}
//此时泛型方法比普通方法只是多了一个 <E>。
public class Test0124_1 {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<String>();
myClass.method1("hello");
myClass.method2("gg");
}
}
(3)通配符(重点)
① ? 可以接收任意类型
用于方法中,表示可以接收任意类型的泛型类。
只能取得类中数据,不能修改数据。因为类型不确定,无法设置确定类型。
② ? extends 类:设置/取得泛型上限
- eg: ? extends Number:表示泛型必须是Number及其子类。
- 用在类上 T extends 类:T必须是类或类的子类。
- 用在方法上 ? extends 类:只能接收类或其子类的泛型类。
只能取得类中属性值,不能修改值(发生父类到子类的向下转型,需要强转。由于具体子类不确定,因此无法转型)
③ ? super 类:取得泛型下限—只能用于方法中
eg: ? super String :表示此方法只能取得String及其父类Object
- 可以设置属性值(子类到父类是自动的向上转型)
class Message<T>{
private T message;
public Message() {
}
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public Message(T message) {
this.message = message;
}
}
public class Test0124_1{
public static void main(String[] args) {
Message<String> message = new Message();
message.setMessage("hello xatu");
fun(message);
}
public static void fun(Message<? super String> temp) {
temp.setMessage("xatu!");
System.out.println(temp.getMessage());
}
}
运行结果:
xatu!
注意:上限可以用在声明,不能修改;而下限只能用在方法参数,可以修改内容。
④泛型接口
//子类继续保持泛型
interface IInterface<T>{
T test(T t);
}
//为子类保留接口
class InterfaceImpl<T> implements IInterface<T>{
}
//子类定义时确定好类型
class InterfaceImpl implements IInterface<String>{
}
在子类定义时继续使用泛型:
interface IMessage<T>{
public void print(T t);
}
class MessageImpl<T> implements IMessage<T> {
@Override
public void print(T t) {
System.out.println(t);
}
}
public class Test0124_1{
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("hello xatu");
}
}
运行结果:
hello xatu
在子类实现接口的时候明确给出具体类型:
interface IMessage<T>{
public void print(T t);
}
class MessageImpl implements IMessage<String> {
@Override
public void print(String t) {
System.out.println(t);
}
}
public class Test0124_1{
public static void main(String[] args) {
IMessage<String> msg = new MessageImpl();
msg.print("hello xatu!!!");
}
}
运行结果:
hello xatu!!!
⑤*** 类型擦除(语法糖 ) ***
泛型信息仅存在于代码编译阶段,进入JVM之前,与泛型相关的信息就会被擦除掉,专业术语:类型擦除
换句话说,泛型类与普通类在Java虚拟机内没有任何区别。
如:泛型、自动拆装箱
class MyClass<T>{
private T message;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public void testMethod1(T t) {
System.out.println(t);
}
}
public class Test0124_1{
public static void main(String[] args) {
MyClass<String> myClass1 = new MyClass<>();
MyClass<Integer> myClass2 = new MyClass<>();
System.out.println(myClass1.getClass() == myClass2.getClass());
}
}
结果为true。MyClass< String >和MyClass< Integer >在JVM中的Class都是MyClass.class。
泛型类进入JVM之前会进行类型擦除,之前泛型类的类型参数若没有指定上限,会被擦除为Object类型。如果指定上限,则类型参数会被替换成相应类型上限。
import java.lang.reflect.Field;
class MyClass<T,E>{
private T message;
private E text;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
public E getText() {
return text;
}
public void setText(E text) {
this.text = text;
}
public void testMethod(T t) {
System.out.println(t);
}
}
public class Test0124_1{
public static void main(String[] args) {
MyClass<String,Integer> myClass1 = new MyClass<>();
Class cls = myClass1.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getType());
}
}
}
运行结果:
class java.lang.Object
class java.lang.Object