目录
预备知识:
jdk1.5新特性:泛型 枚举 注解/可变参数/foreach循环/静态导入/向上转型(90%):父类 父类引用=子类实例 //以物换物/向下转型(1%):子类 子类引用=(子类)父类实例
(?/?extends类:/T extends 类:/? extends 类:/? super 类:)
回顾C语言,普通指针提供两方面的信息,1地址2内存大小
而void*只有地址信息.没有内存大小信息
一个函数需要支持多种不同类型的参数就可以使用void*
起到的效果:让一个类或者方法可以使用不同类型的参数--引入泛型
jdk1.5新特性:泛型 枚举 注解
可变参数
要求方法可以接收任意个整数并且返回他们相加的结果
类型 参数名称
- 一个方法有且只有一个可变参数,放在方法的最后一个参数
- 可变参数的本质----还是数组
foreach循环
foreach语法可以和很多类搭配,只要这个类实现了iterable接口,就可以使用
---用于数组与类集的简单输出(修改的话还是用for循环)
for(数据类型 临时变量 : 数组(集合)) { // 循环次数为数组长度,而每一次循环都会顺序取出数组中的一个元素赋值给临时变量 }
举例:
public class TestDemo {
public static void main(String[] args) {
int[] data = new int[] { 1, 2, 3, 4, 5 }; // 原始数组
for (int i : data) { // 将数组中每个元素赋值给i
System.out.println(i); // 这种循环避免了角标的问题
}
}
}
静态导入
package www.se.SE.util;
public class MyMath{
public static int add(int x,int y){
return x+y;
}
public static int mul(int x,int y){
return x*y;
}
}
package www.se.SE.util;
import static www.se.SE.util.MyMath.*;//静态导入
public class Test1{
public static void main(String[] args){
System.out.println(add(10,20));
System.out.println(mul(30,10));
}
}
描述坐标的属性类:
1 私有Object类属性x 私有Object类属性y
2设置x y的值
3自动拆箱 把Object类的值强行转换为Integer类型(double /string)
package se.SE.practice;
class point{
private Object x;
private Object y;
public Object getX() {
return x;
}
public void setX(Object x) {
this.x = x;
}
public Object getY() {
return y;
}
public void setY(Object y) {
this.y = y;
}
}
public class Thread1 {
public static void main(String[] args) {
point point1 = new point();
point1.setX(10);
point1.setY(20);
int x = (Integer) point1.getX();//把Object类型的变量强行转为Integer类型
int y = (Integer) point1.getY();//自动拆箱,类型之间的转换只能在引用类型中转换
System.out.println(x + " " + y);
}
}
注意:由于设置方的错误,将坐标内容设置成了double类型(eg.20.9)与String类型(eg.北纬89°),但是接收方不知道
不可以将String类型强制转换为int 类型,否则系统会报出:ClassCastException异常,
总结:向下转型存在安全隐患
向上转型(90%):父类 父类引用=子类实例 //以物换物
天然发生(认爹)
应用场景:参数统一化
test(new Person());
//per=new Studnet();//子类指向父类
test(new Student());
Person per=new Student();//子类一定可以变成父类 向上转型
per.fun();
向下转型(1%):子类 子类引用=(子类)父类实例
//剩下1%不转(认儿)
Student stu=(Student)per;//向下转型
需要强转,发生向下转型之前,一定首先发生向上转型
否则会抛出一个ClassCastException(运行时异常,类型转换异常,发生在两个毫无关系的类之间强转时)
泛型类:
所谓的泛型,就是类定义的时候,并不会设置类的属性和方法参数的任何类型
在使用的时候再定义
格式:
class MyClass<T>{
private T value1;
public T getValue1() {
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
}
语法:
T:
被称为类型参数,用于指代任意类型
代表一般的类
E:
泛型类中的属性
K V :
见于map集合hsjb
package se.SE.practice;
class MyClass<T>{
private T value1;
public T getValue1() {
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
}
public class Test{
public static void main(String[] args) {
MyClass<String> myClass=new MyClass<String>( );//使用的时候定义类型
myClass.setValue1("2019a");
System.out.println(myClass.getValue1());
MyClass<Integer> myClass2=new MyClass<Integer>();
myClass2.setValue1(10);
System.out.println(myClass2.getValue1());
}
}
泛型只允许接收类,所有基本类型必须使用包装类
泛型方法
格式:
<T>:表示此方法是泛型方法
T:参数t的返回值类型
public <T> void MyMethod(T t){
System.out.println(t);
}
package se.SE.practice;
class MyClass{
public <T> void MyMethod(T t){
System.out.println(t);
}
}
public class Test{
public static void main(String[] args) {
MyClass myClass=new MyClass();
myClass.MyMethod(10);
myClass.MyMethod("78A");
myClass.MyMethod(10.667);
}
}
泛型类与泛型方法共存时:
泛型类中的类型参数与泛型方法类型参数没有关系,泛型方法中的类型参数始终以自己定义的类型参数为准
规范:
泛型方法类型参数与泛型类的类型参数不要同名
引入通配符:
引入泛型后,在方法的参数上,参数的类型较多时,需要大量重载方法
通配符
用在方法中,表示泛型可以接受任意类型的泛型类
只能取得类中数据,不能修改数据(因为类型不确定,无法设置类型)
?
:表示可以接收任意类型
格式:
方法声明(类名<?> 参数名){
方法体
}
package se.SE.practice;
class MyClass<T>{
private T value1;
public T getValue1() {
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
public <E> void MyMethod1(E t){
System.out.println(t);
}
}
public class Test{
public static void main(String[] args) {
MyClass myClass=new MyClass();
myClass.setValue1(123);//设置value1的值为123
print(myClass);
}
public static void print(MyClass<?> myClass){//通配符 传进来的myclass是什么类型 就在方法中定义什么类型
myClass.getValue1();
}
}
?extends类:
表示设置或者取得泛型上限
?extends Number
表示泛型必须是Number及其子类----也就是说?必须继承Number这个类
package se.SE.practice;
class MyClass<T extends Number>{
private T value1;
public T getValue1() {
return value1;
}
public void setValue1(T value1) {
this.value1 = value1;
}
public <E> void MyMethod1(E t){
System.out.println(t);
}
}
public class Test{
public static void main(String[] args) {
MyClass<Double> myClass=new MyClass();
myClass.setValue1(78.3);//设置value1的值为78.3
print(myClass);
}
public static void print(MyClass<? extends Number> myClass){//通配符
myClass.getValue1();
}
}
- 用在类上:
T extends 类:
表示T必须是类或者类的子类
- 用在方法上:
? extends 类:
表示只能接收类或者子类的泛型类,只能取得值不能修改值
(发生在父类到子类的向下转型,需要强转,由于具体子类不确定,因此无法强转)
? super 类:
只能用在方法中,取得泛型下限
eg?super String 表示只能取得String以及其父类,只能用于方法中
public static void print(MyClass<? super String> myClass){//通配符
myClass.getValue1("HELLO");//设置value1的值为HELLO
myClass.getValue1();
}
泛型的下限可以设置属性值,因为子类到父类自动的向上转型
泛型接口
泛型接口没有定义类型,子类实现接口有两种选择
- 1子类继续保留泛型---子类还是泛型类
第一个T表示子类是泛型类,后面的T表示接口是泛型接口
class MyClass1Impl<T> implements IInterface<T>
- 2子类定义时确定好类型
class MyClass2Impl implements IInterface<String>
package se.SE.practice;
interface IInterface <T> {//定义泛型接口IInterface
T test(T t);
}
//子类实现接口继续保留泛型----子类还是泛型类
//class MyClass1Impl<T> implements IInterface<T> {
// @Override
// public T test(T t) {
// return t;
// }
//}
//子类实现接口定义类型-----子类定义了其他类型(本例中定义了String类)
class MyClass2Impl implements IInterface<String>{
@Override
public String test(String s){
return s;
}
}
public class Test {
public static void main(String[] args) {
IInterface<String> iInterface = new MyClass2Impl<String>() ;
System.out.println(iInterface.test("Welcome to my world!"));
}
}
类型擦除
泛型信息仅存在于代码的源码编译阶段,进入JVM之前与泛型相关的信息会被擦除掉,也就是泛型擦除
java语法糖:
仅存在于源码编译阶段,编译后就消失不见-----典型:泛型/自动拆装箱/String常量的加号
作用:方便程序员的开发
通俗点讲:泛型类和普通类在java虚拟机内没有任何区别