文章目录
- 一:double与float
- 二:类型转换造成精度丢失
- 三:Switch表达式
- 四:break 研究
- 五:break 标签名
- 六:continue 标签
- 七:字符串
- 八:数组
- 九:权限修饰符
- 十:局部变量
- 十一:this
- 十二:构造方法
- 十三:静态方法和非静态方法
- 十四:static 定义静态区域
- 十五:Java虚拟机
- 十六:Math 随机数
- 十七:重写父类方法
- 十八:继承机制调用构造方法顺序
- 十九:instanceof 关键字
- 二十:不定参数
- 二十一:抽象类的特点
- 二十二:继承与多态配合的新发现
- 二十三:包的特点
- 二十四:static final
- 二十五:final 方法特性
- 二十六:方法覆盖
- 二十七:final 类
- 二十八:成员内部类
- 二十九:内部类
- 三十:栈与堆装的是什么
- 三十一:局部内部类
- 三十二:匿名内部类
- 三十三:静态内部类
- 三十四:内部类的继承
- 三十五:异常
- 三十六:异常处理机制
- 三十七:finally 语句块不会执行的4种情况
- 三十八:throws 关键字
- 三十九:throw 关键字
- 四十:catch 语句的顺序不可调换
- 四十一:异常的使用原则
- 四十二:Iterator 迭代器
- 四十三丶List 集合
- 四十四丶ArrayList 集合
- 四十五:LinkedList 集合
- 四十六:Set 集合
- 四十七:HashSet 集合
- 四十八:TreeSet 集合
- 四十九:Map 集合
- 五十:HashMap 集合
- 五十一:TreeMap 集合
- 五十二:Flie 类
- 五十三:缓存
- 五十四:反射能做什么
- 五十五:反射机制的意义
- 五十六:定义 Annotation 类型
- 五十七:访问 Annotation 信息
- 五十八:使用枚举类型设置常量
- 五十九:深入了解枚举类型 之 操作枚举类型成员的方法
- 六十:深入了解枚举类型 之 枚举类型中的构造方法
- 六十一:枚举类型的优势
- 六十二:泛型 诞生的意义
- 六十三丶泛型的特点
- 六十四丶泛型的常规用法
- 六十五丶常用的被泛型化的集合类
- 六十六丶泛型集合规范
- 六十七丶泛型的高级用法
原创不易,只想要一个赞,感谢!
一:double与float
在默认情况下,小数都被看作 double 型,若使用 float 型小数,则需要在小数后面添加F 或 f。可以使用后缀 d 或 D 来明确表明这是一个 double 类型数据,不加d不会出错,但声明
float 型变量时如果不加 f,系统会认为变量是 double 类型。
二:类型转换造成精度丢失
执行显示类型转换时,可能会导致精度丢失。
举例说明:
byte b = (byte)129;
高精度转低精度的显示类型转换,程序虽然不报错能执行,但b的值为:-127。
三:Switch表达式
Switch 语句中表达式的值必须是整型、字符型或字符串类型,字符串类型是在JDK 1.7添加的新特性
四:break 研究
break 只会跳出一层循环
五:break 标签名
break 标签名(任意名),可以在跳出当前循环的前提下,再跳出 标签名指定的循环体,例如:
Loop:for(int i = 0;i<3;i++) {
for(int j=0;j<6;j++) {
if(j == 4) {
break Loop;
}
System.out.println("i=" + i + "j=" + j);
}
}
在 j==4的时候,不仅跳出了内层循环,同时也跳出了外层给循环。
六:continue 标签
continue 也支持标签功能
标签名:循环体{
continue 标签名;
}
七:字符串
字符串的值都被称为字符串常量
八:数组
对于整型数组,无论一维还是二维,系统都会默认为每个元素赋初始值为0
九:权限修饰符
默认的权限修饰符为:default,只有包内的任何类可以进行访问
十:局部变量
局部变量在使用时必须进行赋值或初始化,否则会出现编译错误
十一:this
this 关键字除了可以调用成员变量、成员方法之外
【1】、调用成员变量
【2】、调用成员方法
【3】、★作为方法的返回值
【4】、★调用类中的构造方法
举例验证【3】:
public Book getBook(){
return this; //返回 Book 类引用
}
举例验证【4】:
public Two() {
this("this 调用有参构造方法");
System.out.println("无参构造方法");
}
public Two(String name) {
System.out.println("有参构造方法");
}
注意:只可以在无参构造方法中的第一句使用 this 调用有参构造方法,是第一句噢!
十二:构造方法
如果在类中定义的构造方法都不是无参的构造方法,那么编译器也不会为类设置一个默认的无参构造方法,当试图调用无参构造方法实例化一个对象时,编译器会报错。
结论:只有在类中没有定义任何构造方法,编译器才会在该类中自动创建一个不带参数的构造方法。
十三:静态方法和非静态方法
1、静态方法中不可以直接调用非静态方法
2、静态方法中不可以使用 this 关键字
3、在非静态方法中可以调用静态方法和静态变量
代码举例验证:
public class StaticTest {
final static double PI = 3.1415;
static int id;
public static void method1() {
System.out.println("method1方法被调用");
}
//正确
public void method2() {
System.out.println(StaticTest.PI);
System.out.println(StaticTest.id);
StaticTest.method1();
}
public static StaticTest method3() {
method2(); //报错
return this; //报错
}
}
十四:static 定义静态区域
如果在执行类时,希望先执行类的初始化动作,可以使用 static 定义一个静态区域。例如:
public class three {
static{
System.out.println("苹果");
}
public static void main(String[] args) {
System.out.println("香蕉");
}
}
运行结果:
苹果
香蕉
结论: 静态区域 会在main()方法前先执行
十五:Java虚拟机
Java虚拟机 视为“垃圾”对象的两种情况:
1、对象引用超过其作用范围
2、将对象赋值为 null
虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由 new 操作符创建的对象,某些对象不是通过new 操作符在内存中获取存储空间的。
十六:Math 随机数
Math.random()(大数-小数),得到随机正数
Math.random()(小数-大数),得到随机负数
十七:重写父类方法
当重写父类方法时,修改方法的权限只能从小的范围到大的范围改变
举个例子:
父类中有方法:
protected void doSomething(){}
只能修改为:
public void doSomething(){}
十八:继承机制调用构造方法顺序
首先是顶级父类,然后是上一级父类,最后是子类。也就是说,实例化子类对象时首先要实例化父类对象,然后再实例化子类对象,所以在子类构造方法访问父类的构造方法之前,父类已经完成实例化操作。
十九:instanceof 关键字
如果不是继承关系,就不能用 instanceof 去做判断
因为从概念就可以解释:instanceof 是判断父类对象是否为子类对象的实例
二十:不定参数
不定长参数方法:
public static int add(int...a){
...
}
其实这个不定参数a就是一个数组,编译器会将(int…a)这种形式看作是(int[]a)
二十一:抽象类的特点
1、抽象类不可以实例化对象
2、抽象类除了被继承之外没有任何意义
3、只要类中有一个抽象方法,此类就被标记为抽象类
4、抽象类被继承后需要实现其中所有的抽象方法
二十二:继承与多态配合的新发现
父类a定义了一个h方法
将子类b继承a
要求:在子类中覆盖父类中的这个h方法并修改内容,并创建一个子类对象将它向上转型到基类并调用这个方法
发现: 根据结果看出,运行的是覆盖重写后的方法,父类里的原方法并不执行。
结论:
从这一点中我们可以看出,虽然是向上转型赋值给了基类,但其实际上这个对象代表的是子类,只是说这个对象可以说是父类的对象,因为子类对象也算是父类的对象,但不能说父类对象是子类对象,所以调用的方法自然是重写后的方法。
源代码证明:
package chapter10;
class Three{
public void a() {
System.out.println("a");
}
public void b() {
System.out.println("b");
}
}
public class two extends Three{
public void b() {
System.out.println("哈哈");
}
public static void main(String[] args) {
Three three = new two();
three.b();
three.a();
}
}
二十三:包的特点
1、同一个包中的类相互访问时,可以不指定包名。
2、【注意】当使用 import 指定了一个包中的所有类时,并不会指定这个包的子包中的类,如果用到这个包中的子类,需要再次对子包作单独引用。
3、Import 关键字除了导入包之外,还可以导入静态成员。
二十四:static final
在Java 中定义全局常量,通常使用 public static final 修饰,这样的常量只能在定义时被赋值。
二十五:final 方法特性
1、定义为 final 的方法执行效率要高于非 final 的方法。
2、final 方法不能被覆盖。
二十六:方法覆盖
方法的覆盖必须满足一个对象向上转型为它的基本类型并调用相同方法这样一个条件
二十七:final 类
1、final 的类不能被继承
2、final 类不允许其他人对这个类进行任何改动
3、final 类中的所有方法都被隐式设置为 final形式
4、final 类中的成员变量可以被定义为 final 或 非final形式
二十八:成员内部类
1、在一个类中使用内部类,可以在内部类中直接存取其所在类的私有变量
2、【√】在外部类中调用内部类方法
3、【√】在外部类实例化内部类对象引用
4、【√】在外部类方法,返回值为内部类引用
5、【×】外部类不可以直接访问内部类成员变量
6、【√】使用内部类对象引用调用外部类成员变量y
7、【√】使用内部类实例化内部类对象
8、【×】不能在new 操作符之前使用外部类名称实例化内部类对象,而是应该使用外部类的对象来创建其内部类的对象
举例:
OuterClass 为外部类、innerClass 为内部类
方法一:
OuterClass out = new OuterClass();
OuterClass.innerClass in2 = out.new innerClass();
方法二:
OuterClass.innerClass in2 = new OuterClass().new innerClass(); //通过外部类的对象
二十九:内部类
非内部类不能被声明为 private 或 protected 访问类型。
三十:栈与堆装的是什么
在内存中所有对象均被放置在堆中,方法以及方法中的形参或局部变量放置在栈中。
三十一:局部内部类
interface OutInterface2{ //定义一个接口
}
public class OuterClass3 {
public OutInterface2 doit(final String x) { //doit() 方法参数为 final 类型
//在 doit() 方法中定义一个内部类
class lnnerClass2 implements OutInterface2{
public lnnerClass2(String s) {
s = x;
System.out.println(s);
}
}
return new lnnerClass2("doit");
}
}
1、在 doit()方法的外部不能访问该内部类
2、但是该内部类可以访问当前代码块的常量以及此外部类的所有成员
3、如果需要在方法体中使用局部变量,该局部变量需要被设置为 final 类型,换句话说,在方法中定义的内部类只能访问方法中 final 类型的局部变量
三十二:匿名内部类
实质上匿名内部类就是创建一个实现于 XXX 接口的匿名类对象。
三十三:静态内部类
1、一个静态内部类中可以声明 static成员,但是在非静态内部类中不可以声明静态成员
2、静态内部类有一个最大的特点,就是不可以使用外部类的非静态成员,所以静态内部类在程序开发中比较少见
3、静态内部类不可以直接调用外部类的非静态成员变量
4、进行程序调试时,如果在每一个 Java 文件中都设置一个主方法,将出现很多额外代码,而程序本身并不需要这些主方法,为了解决这个问题,可以将主方法写入静态内部类中
三十四:内部类的继承
必须要满足四个条件:
1、继承内部类的前面要跟随外部类名+"."
2、在某个类继承内部类时,必须硬性给予这个类一个带参数的构造方法
3、并且该构造方法的参数为需要继承内部类的外部类的引用
4、在构造方法体中使用a.super()语句,这样才为继承提供了必要的对象引用
源代码举例:
class ClassA{
class ClassB{
}
}
public class OutputInnerClass extends ClassA.ClassB{
public OutputInnerClass(ClassA a) {
a.super();
}
}
三十五:异常
1、一个程序在执行期间发生的事件,它中断了正在执行的程序的正常指令流。
2、当程序运行结果报告发生了异常后,系统不再执行下去,提前结束。也就是说,异常产生后,如果不做任何处理,程序就会被终止。
三十六:异常处理机制
1、可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时在其他地方处理异常。
三十七:finally 语句块不会执行的4种情况
1、在 finally 语句块中发生了异常
2、在前面的代码中使用 System.exit() 退出程序
3、程序所在的线程死亡
4、关闭CPU
三十八:throws 关键字
1、通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分割。
2、使用 throws 关键字将异常抛给上一级后,如果不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的代码。
三十九:throw 关键字
1、throw 关键字通常用于方法体中,并且抛出一个异常对象。程序在执行到 throw 语句时立刻终止,它后面的语句都不执行。
2、throw 抛出异常后,如果想在上一级代码中捕获并处理异常,则需要在抛出异常的方法中使用 throws 关键字在方法的声明中指明要抛出的异常。
3、如果要捕捉 throw 抛出的异常,则必须使用 try-catch 语句块。
四十:catch 语句的顺序不可调换
由于Exception 是所有异常的父类,如果将 catch(Exception e)代码块放在其他几个代码块的前面,后面的代码块将永远得不到执行,也就没有什么意义了。
四十一:异常的使用原则
1、在当前方法声明中使用 try-catch 语句捕获异常。
2、一个方法被覆盖时,覆盖它的方法必须抛出相同的异常或异常的子类。
3、如果父类抛出多个异常,则覆盖方法必须抛出那些异常的一个子集,不能抛出新异常。
四十二:Iterator 迭代器
Iterator 的 next()方法返回的是Object类型的数据。
四十三丶List 集合
1、List 集合中的元素允许重复,各元素的顺序就是对象插入的顺序。
四十四丶ArrayList 集合
【优点】
1、实现了可变的数组
2、允许保存所有元素,包括null
3、可以根据索引位置对集合进行快速的随机访问
【缺点】
1、向指定的索引位置插入对象或删除对象的速度较慢
四十五:LinkedList 集合
【优点】
1、便于向集合中插入和删除对象,需要向集合中插入、删除对象时,使用LinkedList 类实现的List集合 的效率较高
【缺点】
1、对于随机访问集合中的对象,使用 LinkedList 类实现List集合效率较低
四十六:Set 集合
1、Set 集合中的对象不按特定的方式排序,只是简单地把对象加入集合中。
2、Set 集合中不能包含重复对象
3、Set 集合有一个约束条件,传入的 Collection 对象不能有重复值,否则可能出现一些问题。
四十七:HashSet 集合
【特征】
1、它不保证 Set 的迭代顺序,特别是它不保证该顺序恒久不变。
2、此类允许使用 null 元素
四十八:TreeSet 集合
【特征+优点】
1、在遍历集合时按照自然顺序递增排序,也可以按照指定比较器递增排序,即可以通过比较器对用 TreeSet 类实现的Set 集合中的对象进行排序。
四十九:Map 集合
1、Map 集合没有继承 Collection 接口,其提供的是 key 到 value 的映射。
2、Map 中不能包含相同的 key,每个key 只能映射一个 value 。
3、key 还决定了存储对象在映射中的存储位置,但不是由 key 对象本身决定的,而是通过一种“散列技术”进行处理,产生一个散列码的整数值。散列码通常用作一个偏移量,该偏移量对应分配给映射的内存区域的起始位置,从而确定存储对象在映射中的存储位置。
4、Map 集合中允许值对象是 null。
五十:HashMap 集合
【特点】:
1、HashMap 类是基于哈希表的 Map 接口的实现
2、允许使用null 值 对 null键
3、HashMap 通过哈希表对其内部的映射关系进行快速查找
4、HashMap 不保证映射的顺序,特别是它不保证该顺序恒久不变。
【优势】:
1、HashMap 类实现的 Map 集合添加和删除映射关系效率更高。
五十一:TreeMap 集合
【特点】:
1、不允许键对象是 null
2、集合中的映射关系具有一定的顺序。
【缺点】:
1、在添加、删除和定位映射关系时,TreeMap 类比 HashMap 类性能稍差。
【优点】:
1、TreeMap 实现的 Map 集合中的映射关系是根据键对象按照一定的顺序排列的。
五十二:Flie 类
1、用来创建一个文件对象
2、File 类中的方法,可实现创建、删除、重命名文件等操作。
3、可获取文件本身的一些信息,如文件所在目录、文件的长度、文件读写权限等。
五十三:缓存
缓存是I/O 的一种性能优化
五十四:反射能做什么
1、访问构造方法
2、访问成员变量
3、访问方法
4、使用 Annotaion 功能
五十五:反射机制的意义
利用反射机制,可以在程序运行时访问类的所有描述信息(经常需要访问的有类的构造方法、成员变量和方法),实现逆向控制程序执行的过程。
利用Annotation 功能,可以对类、构造方法、成员变量、方法、参数等进行注释,在程序运行时通过反射可以获取这些信息,根据读取的信息也可以实现逆向控制程序的执行过程。
五十六:定义 Annotation 类型
1、定义 Annotation 类型的关键字为:@interface
2、如果在所定义的 Annotation 类型中只包含一个成员,通常将成员名称命名为 value
3、在为 Annotation 类型定义成员时,可以为成员设置默认值
4、@Target 来设置 Annotation 类型适用的程序元素种类
5、@Retention 可以设置 Annotation 的有效范围
五十七:访问 Annotation 信息
1、如果在定义 Annotation 类型时,将@Retention 设置为 RetentionPolicy.RUNTIME,那么在运行程序时通过反射就可以获取相关的 Annotation 信息,如获取构造方法、字段和方法的 Annotation 信息。
2、isAnnotationPresent(Class<? extends Annotation> annotationClass):
用来查看是否添加了指定类型的 Annotation,如果是返回true,否则返回false
3、getAnnotation(Class annotationClass):
用来获得指定类型的 Annotation
4、getAnnotations():
用来获得所有的 Annotation,该方法返回一个 Annotation数组
5、getParameterAnnotations:
用来获得为所有参数添加的 Annotation,将以 Annotation 类型的二维数组返回,在数组中的顺序与声明的顺序相同,如果没有参数则返回一个长度为0的数组;如果存在未添加 Annotation 的参数,将用一个长度为0 的嵌套数组占位
五十八:使用枚举类型设置常量
1、enum 是定义枚举类型的关键字
2、当需要在程序中使用枚举类型的常量时,可以使用 枚举类型.常量名来表示,例如:
enum Constants2{ //定义枚举类型
Constants_A,Constants_B
}
Constants2.Constants_A 使用枚举类型的常量
3、对于枚举类型作为参数的方法,调用者也只能传递枚举类型的参数作为实参
4、枚举类型可以在类的内部或外部进行定义
五十九:深入了解枚举类型 之 操作枚举类型成员的方法
1、用户可以将一个枚举类型看作是一个类
2、使用枚举类型成员时直接使用枚举类型名称调用枚举类型成员即可。例如:Constants2.Constants_A
3、枚举类型常用的方法:values()、valueOf()、compareTo()、ordinal()
(1)values():该方法将枚举类型的成员变量实例以数组的形式返回,也可以通过该方法获取枚举类型的成员
代码实例:
public class ShowEnum {
//将常量放置在枚举类型中
enum Constants2{
Constants_A,Constants_B
}
public static void main(String[] args) {
for(int i=0; i<Constants2.values().length;i++) { //循环由 values()方法返回的数组
out.println("枚举类型成员变量:" + Constants2.values()[i]); //将枚举成员变量打印
}
}
}
(2)valueOf 与 compareTo()
valueOf():可以将普通字符串转换成枚举类型
compareTo():用于比较两个枚举类型对象定义时的顺序
代码实例:
public class EnumMethodTest {
//将常量放置在枚举类型中
enum Constants2{
Constants_A,Constants_B
}
//定义比较枚举类型方法,参数类型为枚举类型
public static void compare(Constants2 c) {
for(int i=0; i<Constants2.values().length; i++) {
System.out.println(c + "与" + Constants2.values()[i] + "的比较结果为:"
+ c.compareTo(Constants2.values()[i])); //将比较结果返回
}
}
public static void main(String[] args) {
compare(Constants2.valueOf("Constants_B"));
}
}
(3)ordinal():获取某个枚举对象的位置索引值
代码举例:
public class EnumIndexTest {
enum Constants2{ //将常量放置在枚举类型中
Constants_A,Constants_B,Constants_C
}
public static void main(String[] args) {
for(int i=0; i<Constants2.values().length; i++) {
//在循环中获取枚举类型成员的索引位置
System.out.println(Constants2.values()[i] + "在枚举类型中位置索引值"
+Constants2.values()[i].ordinal());
}
}
}
六十:深入了解枚举类型 之 枚举类型中的构造方法
1、在枚举类型中,可以添加构造方法,但是规定这个构造方法必须为 private 修饰符所修饰。
2、定义一个有参构造方法后,需要对枚举类型成员相应地使用构造方法,如 Constants_A(“我是枚举成员 A”) 和 Constants_D(3),相应地都要使用参数为String 型和参数为 int 型的构造方法
实例:(60.1)
public class EumIndexTest {
//将常量放置在枚举类型中
enum Constants2{
//定义带参数的枚举类型成员
Constants_A("我是枚举成员A"),
Constants_B("我是枚举成员B"),
Constants_C("我是枚举成员C"),
Constants_D(3);
private String description;
private int i = 4;
private Constants2() {
}
private Constants2(String description) {
this.description = description;
}
private Constants2(int i) {
this.i = this.i + i;
}
public String getDescription() {
return description;
}
public int getI() {
return i;
}
}
public static void main(String[] args) {
for(int i=0; i<Constants2.values().length; i++) {
System.out.println(Constants2.values()[i] + "调用 getDescription()方法为:"
+ Constants2.values()[i].getDescription());
}
System.out.println(Constants2.valueOf("Constants_D") + "调用 getl()方法为:"
+ Constants2.valueOf("Constants_D").getI());
}
}
3、使用 valueof(),参数里的字符串必须在枚举类型中被定义,否则会报异常
4、枚举类型中的构造方法设置为 private,可以防止客户代码实例化一个枚举对象
5、除了可以使用 60.1 中所示的方式定义 getDescription() 方法获取枚举类型成员定义时的描述之外,还可以将这个 getDescription() 方法设置在接口中,使枚举类型实现该接口,然后使每个枚举类型实现接口中的方法
实例(60.2)
import static java.lang.System.out;
interface d{
public String getDescription();
public int getI();
}
public enum AnyEnum implements d{
//可以在枚举类型成员内部设置方法(实现接口中的抽象方法)
Constants_A{
@Override
public String getDescription() {
return ("我是枚举成员A");
}
@Override
public int getI() {
return i;
}
},
Constants_B{
@Override
public String getDescription() {
return ("我是枚举成员B");
}
@Override
public int getI() {
return i;
}
},
Constants_C{
@Override
public String getDescription() {
return ("我是枚举成员C");
}
@Override
public int getI() {
return i;
}
},
Constants_D{
@Override
public String getDescription() {
return ("我是枚举成员D");
}
@Override
public int getI() {
return i;
}
};
private static int i = 5;
public static void main(String[] args) {
for(int i=0; i<AnyEnum.values().length; i++) {
out.println(AnyEnum.values()[i] + "调用 getDescription() 方法为:"
+ AnyEnum.values()[i].getDescription());
out.println(AnyEnum.values()[i] + "调用 getI() 方法为:"
+ AnyEnum.values()[i].getI());
}
}
}
6、可以在枚举类型成员内部设置方法
7、既然枚举类型可以看作是一个类,那么 main()主方法也可以写在枚举类型里!
六十一:枚举类型的优势
1、类型安全
2、紧凑有效的数据定义
3、可以和程序其他部分完美交互
4、运行效率高
六十二:泛型 诞生的意义
概念:
在没有出现泛型之前,Java 也提供了对 Object 的引用“任意化”操作,这种“任意化”操作就是对 Object 引用进行向下转型及向上转型操作,但某些强制类型转换的错误也许不会被编译器捕捉,而在运行后出现异常,可见强制类型转换存在安全隐患,所以在此提供了泛型机制。
代码演示意义:
public class Test {
private Object b; //定义 Object 类型成员变量
private Object getB() {
return b;
}
public void setB(Object b) {
this.b = b;
}
public static void main(String[] args) {
Test t = new Test();
t.setB(new Boolean(true)); //向上转型操作
System.out.println(t.getB());
t.setB(new Float(12.3));
Float f = (Float)(t.getB()); //向下转型操作
/*
* t.setB(new Float(12.3));
* Integer f = (Integer)(t.getB());
* System.out.println(f);
*/
System.out.println(f);
}
}
如果将写法换成注释部分的话:
虽然不存在语法错误,可以被编译器接受,但在执行时会出现 ClassCastException 异常。这样看来,向下转型操作通常会出现问题,而泛型机制有效地解决了这一问题。
六十三丶泛型的特点
1、使用泛型定义的类在声明该类对象时可以根据不同的需求指定真正的类型,而在使用类中的方法传递或返回数据类型时将不再进行转型转换操作,而是使用在声明泛型类对象时“<>”符号中设置的数据类型。
2、使用泛型这种形式将不会发生ClassCastException 异常,因为在编译器中就可以检查类型匹配是否正确。
举例:
OverClass over2 = new OverClass();
over2.setOver(12.3f);
//此时如果用下面这种写法,编译器会直接报错
Integer i = over2.getOver();
解析:由于 over2 对象在实例化时已经指定类型为 Float,而最后一条语句却将该对象获取出的 Float 类型值赋予 Integer 类型,所以编译器会报错。
3、在泛型中,成员变量与成员方法都可以设置为泛型,但是要统一。
举例:
【错误写法】:
public class OverClass<T> {
一:
private int over;
public T getOver() {
return over;
}
二:
private T over;
public int getOver(){
...;
}
这两种写法都是错误的
}
【正确写法】:要统一
public class OverClass<T> {
private T over;
public T getOver() {
return over;
}
}
六十四丶泛型的常规用法
1、在定义泛型类时,可以声明多个类型
例如:
Student<T1,T2>
Student:泛型类名称
这样实例化对象时就可以指定多个类型
ArrayClass<String,Boolean> a = new ArrayClass<String,Boolean>();
2、在使用泛型机制时声明一个数组,但是不可以使用泛型来建立数组的实例。
例如:
public class ArrayClass<T1> {
private T1[] array = new T1[10]; //错误
}
六十五丶常用的被泛型化的集合类
ArrayList、HashMap<K,V>、HashSet、Vector
六十六丶泛型集合规范
一般类型名称使用 T 来表达,而容貌其的元素使用 E 来表达。
六十七丶泛型的高级用法
1、限制泛型可用类型
(1)默认可以使用任何类型来实例化一个泛型类对象,但 Java 中也对泛型类实例的类型作了限制。
(2)使用泛型后,泛型类的类型必须实现或继承了某个接口或类。
举例:
public class LimitClass <T extends List> { //限制泛型的类型
public static void main(String[] args) {
//可以实例化已经实现 List 接口的类
LimitClass<ArrayList> l1 = new LimitClass<ArrayList>();
LimitClass<LinkedList> l2 = new LimitClass<LinkedList>();
//这句是错误的,因为 HashMap 没有实现 List() 接口
// LimitClass<HashMap> l3 = new LimitClass<HashMap>();
}
}
(3)当没有使用 extends 关键字限制泛型类型时,默认 Object 类下的所有子类都可以实例化泛型对象。
2、使用类型通配符
(1)在泛型机制中,提供了类型通配符,其主要作用时在创建一个泛型类对象时限制这个泛型类的类型实现或继承某个接口或类的子类。要声明这样一个对象可以使用“?”通配符来表示,同时使用 extends 关键字来对泛型加以限制
(2)可以将该实例放置在方法的参数中
举例:
public void doSomething(Test<? extends List> a) {
}
(3)如果使用 A<?>这种形式实例化泛型类对象,则默认表示可以将 A 指定为实例化 Object 及以下的子类类型。
举例:
List<String> l1 = new ArrayList<String>(); //实例化一个 ArrayList 对象
l1.add("成员");
List<?> l2 = l1;
List<?> l3 = new LinkedList<Integer>();
System.out.println(l2.get(0)); //获取集合中的第一个值
3、继承泛型类与实现泛型接口
定义为泛型的类和接口可以被继承和实现
原创不易,只想要一个赞,感谢!