JDK1.5的新特性
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 int add(String msg,int ... data){
int result = 0;
for (int i = 0; i < data.length; i++) {
result += data[i];
}
return result;
}
2.for-each循环
原始数组输出
for (int i = 0; i <data.length ; i++) {
System.out.print(data[i]);
}
从jdk1.5之后对于for循环的使用有了新格式
for(数据类型 临时变量 : 数组(集合) ){
//循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量
}
使用for-each循环输出
for (int i : data) { //将数组中每个元素赋给i
System.out.print(i);//这种循环避免了角标的问题
}
3.静态导入(import)
从jdk1.5开始,如果类中方法全是static方法,则可以直接把这个类的方法导入进来,这样就好比像在主类中定义的方法那样,可以直接在主方法中调用
import static 导入一个类的所有静态域(方法与属性)
import static javaSE.bit.util.Mymath.*
4.泛型:语法糖(类型守门员)
ClassCastException(RuntimeException):在强转时,两个毫无关系的类产生的异常
安全隐患:存在于强转
4.1泛型:在定义时类型不确定(啥类型都可以),只有在具体的使用时才能确定类型。
4.2泛型类:
class MyClass<T> {
T value1;
}
其中表示类型参数,用于指代任意类型,不包括基本类型
一般使用单个大写字母来代表类型参数:T代表一般类;E代表元素(Element)或者异常(Exception)
注意:泛型只接受类,所有的基本类型必须使用包装类
引入多个类型
class MyClass<T,E> {
T value1;
E value2;
}
范例:使用泛型定时Point类
class Point<T>{
T x;
T y;
public T getX() {
return x;
}
public void setX(T x) {
this.x = x;
}
public T getY() {
return y;
}
public void setY(T y) {
this.y = y;
}
}
public class TestDemo {
public static void main(String[] args) {
Point<String> p = new Point<String>();
p.setX("东经80度");
p.setY("北纬20度");
String x = p.getX();
String y = p.getY();
System.out.println("x= " + x + "\n" + "y= " + y);
}
}
4.3泛型方法
class MyClass{
public <T> T testMethod(T t) {
System.out.println(t);
return t;
}
泛型方法始终以自己的类型参数为准,与泛型类中的类型参数无关,为了避免混淆,一般使用不同的类型参数来定义泛型类和泛型方法
范例泛型类与泛型方法共存:
class MyClass<T>{
public void testMethod1(T t) {
System.out.println(t);
}
public <T> T testMethod2(T t) {
return t;
}
}
public class GenericMethodTest {
public static void main(String[] args) {
MyClass<String> myClass = new MyClass<>();
myClass.testMethod1("hello 泛型类");
Integer i = myClass.testMethod2(100);
System.out.println(i);
}
}
4.4通配符
问题:引入泛型后参数类型被确定,方法参数只能接收一种类型的泛型类。
public static void fun(Message temp)
1.?通配符。只能用在方法级别,表示指代任意类型的泛型
只能取得泛型对象中的值,无法通过类似setter方法设置值。
由于传入类型无法确定,因此无法设置具体值到相应对象中。
2.?extends 类,表示泛型上限,类和方法均可使用。
类:
class MyClass
此时T必须是Number的子类,设定天花板
方法:
public void fun(MyClass<? extends Number myClass>
?指代任意类型,但是此时必须传入Number及其子类MyClass对象
此时方法依然不能设置值,只能取得值。现在只能确定的是父类,由于子类不确定,此时发生向下转型存在不确定性因此无法设置具体值。
class Message<T extends Number> { // 设置泛型上限
private T message ;
public T getMessage() {
return message;
}
public void setMessage(T message) {
this.message = message;
}
}
public class Test {
public static void main(String[] args) {
Message<Integer> message = new Message() ;
message.setMessage(55);
fun(message);
}
// 此时使用通配符"?"描述的是它可以接收任意类型,但是由于不确定类型,所以无法修改
public static void fun(Message<? extends Number> temp){
//temp.setMessage(100); 仍然无法修改!
System.out.println(temp.getMessage());
}
}
3.?super类,表示泛型下限,只能用在方法级别
public void fun(MyClass<? super String> myClass{
}
此时方法可以设置值,因为发生天然的向上转型。
总结:
1.只有上限通配符可以用在泛型类的声明上, T extends Number,
此时T必须是Number的子类
2.只有下限通配符能在方法中修改泛型对象内容。
4.5泛型接口
1.子类在实现接口时就确定好接口的类型
2.子类实现接口时保留泛型,此时子类也是泛型
interface IMessage<T>{
public void print(T t);
}
//1.子类继续使用泛型
class MessageImpl<T> implements IMessage<T>{
@Override
public void print(T t) {
System.out.println(t);
}
}
//2.子类明确给出具体类型
class MessageImpl2 implements IMessage<String>{
@Override
public void print(String s) {
System.out.println(s);
}
}
public class TestDemo {
public static void main(String[] args) {
IMessage<String> msg=new MessageImpl<>();
msg.print("hello");
IMessage<String> msg2=new MessageImpl2();
msg2.print("HELLO");
}
}
4.6类型擦除
泛型只存在于编译阶段,进入JVM之前,与泛型相关的信息会被完全擦除。
在JVM看来,根本就不存在泛型的概念
泛型类在进行类型擦除时,若未指定泛型的上限,泛型相关信息会被擦除为Object类型,否则,被擦除为相应的类型上限。
class MyClass<T,E extends Number>{
public T t;
public E e;
}
T->Object
E->Number