JAVASE的学习笔记(五)
包装类
为什么需要包装类
Java设计之初由一个基本原则:一切皆对象(先有类才有对象),一切的操作都是需要用对象的形式进行描述。
但是出现不是对象“东西”,基本数据类型不是对象,无法使用对象的形式来进行操作
创建对象之后,那么我们可以通过.运算符调用响应的属性和行为
,操作基本数据类型也想使用对象的形式?
代码
public class Demo01{
public static void main(String...args){
int num = 100;
//将基本数据类型int包装成temp的对象
Int temp = new Int(100);
//使用包装后的对象,调用行为或者属性
temp.m1();
//从对象中取得了基本数据
int result = temp.intValue();
System.out.println("result="+result);
}
}
/**
* 实现基本数据类型int的包装类
*/
public class Int{
private int number;
public Int(int number){
this.number = number;
}
public void m1(){
System.out.println("number="+number);
}
//获取包装类中的数据
public int intValue(){
return this.number;//可以省略this
}
}
系统包装类
数据类型转换(核心)★★
字符串java.lang.String
和基本数据类型之间的转换
- Integer类:
public static int parseInt(String s)
: Integer.parseInt(String s) - Double类:
public static double parseDouble(String s)
- Boolean类: `public static boolean parseBoolean(String s)
- Character包装没有
包装类的使用
- 装箱操作:将基本数据类型变成包装类,每个包装类的构造方法都可以接收各自数据类型的变量
- 拆箱操作:从包装类中提取出包装的数据(基本数据类型),利用Number类提供的上述六个方法
自动装箱拆箱:
public class Demo05{
public static void main(String...args){
Integer obj = 11;//自动装箱 int->Integer,不需要我们在使用构造方法了
int temp = obj;//自动拆箱 Integer->int 实际上底层调用obj.intValue()方法
//包装类可以进行计算
obj++;//自动拆箱过程 obj->int
System.out.println(obj);//自动装箱 int->Integer
System.out.println(temp*obj);//自动拆箱Integer->int
}
}
泛型
概念:泛型就是参数化的类型(传递),使用广泛的类型
使用泛型的原因?
数据类型不明确
- 装入数据的类型(赋值)都被处理Object类型,从而“失去”了自己实际的类型
- 往往我们在获取数据的时候,还需要转换数据类型,效率低下,并且十分容易产生错误
泛型的作用?
- 安全性:在
编译
期间就检查数据类型是否安全(是否匹配) - 省心(高效性):所有的强制类型转换都是变成自动(隐藏)的,提高了代码的重用率
如何定义泛型?
定义格式:使用<任意的字母>
符号
泛型中常用的字母含义(约定)
- T : Type表示类型
- K,V : 代表键值对Key和Value
- E:代表Element
- N:代表Number数字
- ?:表示不确定性
泛型的使用规则
(1)不能使用静态属性上,static修饰的不能使用泛型★★★
(2)使用的时候需要指定数据类型:
a.编译的时候会检查数据的类型
b.获取数据的时候不再需要强制类型转换
(3)泛型使用是不能指定基本数据类型,只能使用基本数据类型对应的包装类
使用泛型定义接口,我们称之为泛型接口,因为泛型中只能由公共的抽象方法和静态的公共常量(不能使用泛型 。接口中,泛型字母只能使用在方法中,不能使用在全局变量中 因为接口只包括全局常量和公共、抽象方法,而全局变量是static的,所以不能用,所以只能用在方法中),JDK8之后可以定义普通的默认方法和静态的默认方法
泛型的使用范围
(1)泛型类:public class Student01<T1,T2>
(2)泛型接口
public interface Info<T>{
T getVar();
void setVar(T value);
}
a.非泛型类实现接口:声明的子类实现接口必须指定“具体的类型”
public class InfoImpl01 implements Info<Double>{
private Double var;
public Double getVar(){
return var;
}
public void setVar(Double var){
this.var = var;
}
}
public class Demo05{
public static void main(String[] args){
//Info<String> info = new InfoImpl01();
Info<Double> info = new InfoImpl01();
info.setVar(123.456);
System.out.println(info.getVar().getClass());
}
}
b.泛型类实现接口
public class InfoImpl02<U> implements Info<U>{
private U var;
public U getVar(){
return var;
}
public void setVar(U var){
this.var = var;
}
}
(3)泛型方法:没有使用泛型类,也没有使用泛型接口,直接在方法上使用泛型
public class FunsTest{
//普通方法
public <T> int test01(T num){
System.out.println(num);
System.out.println(num.getClass());
return 100;
}
public <T> T test02(T num){
System.out.println(num);
System.out.println(num.getClass());
return num;
}
//静态方法
public static <T> String test03(T num){
System.out.println(num);
System.out.println(num.getClass());
return "悟空";
}
public static <T> T test04(T num){
System.out.println(num);
System.out.println(num.getClass());
return num;
}
}
public class Demo06{
public static void main(String[] args){
FunsTest ft = new FunsTest();
ft.test01("悟空");//没有在编译期间检查数据的类型
//会自动将<T>自动变成String,数据决定泛型的类型
//编译不会产生错误
/**不符合规范的,但是是推荐使用*/
//标准写法,不推荐使用
ft.<Integer>test01("八戒");//编译检查了数据类型
}
}
(4)泛型数组
private T[] array ;//只能声明,不能创建
public class Demo07{
public static void main(String[] args){
Dog<String> dog = new Dog<>();
Integer[] temp = m1(1,2,3,4);
System.out.println(java.util.Arrays.toString(temp));
String[] temp01 = m1("悟空","八戒");
System.out.println(java.util.Arrays.toString(temp01));
}
public static <T> T[] m1(T...array){
return array;
}
}
class Dog<T>{
// private T[] array = new T[10];//不能创建
private T[] array ;//只能声明
}
泛型类型之间不存在转换,没有所谓的对象上转型,接口回调
- Student无法转换为Student<0bject>
public class Demo01 {
public static void main(String.. . args){
Student<String> s1 = new Student<>();
s1. setMath("良好”);
s1. setEnglish("中等");
//s1数据就可以传递了
//调用m1方法Student<String>->Student<0bject>
//泛型类型之间转换?
m1(s1);
//错误:不兼容的类型: Student<Str ing>无法转换为Student<0bject>
}
public static void m1 (Student<0bject> temp){
System . out . println(" temp=”+temp) ;
}
}
2.修改代码,将m1中的泛型不指定类型,不指定T就是Object,这种情况违背了使用泛型的意图,丢失了原本的类型,又需要判断类型进行强转
public class Demo02{
public static void main(String...args){
Student<String> s1 = new Student<>();
s1.setMath("良好");
s1.setEnglish("中等");
//s1数据就可以传递了
m1(s1);
}
//Student不写泛型的范围比Student<Object>范围大
public static void m1(Student temp){
//不兼容的类型: Object无法转换为String
//又丢失了你原本的类型,我们又需要判断类型进行强转
String math = temp.getMath();
System.out.println("temp="+temp);
}
}
- ? 通配符:根据你传递的泛型变化而变化
受限的泛型(限定泛型)
- 上限限定使用
extends
关键字,表示这个类型必须是继承某个类或者实现某个接口,也可以是该类的本身或接口的本身
public class Person<T extends Number>
- 下限限定使用super关键字,表示类型是某个类的父类或者是某个接口的父接口,也可以是这个类的接口本身
public class Person<T super Number>//错误:下限限定使用super关键字,不能使用在泛型类和泛型接口中
- 下限限定使用super关键字,不能使用在泛型类和泛型接口中,一般我们使用在泛型的方法传递中
public static void m1(Person<? super Double> temp){
System.out.println(temp);
}
泛型擦除规则
-
声明实现类,实现的接口必须指定"具体的类型"
class Service01 implements UserService<String>{}
-
实现类和接口同时擦除(不写),使用Object
class Service02 implements UserService{
public void add(Object t){}}
-
实现类是泛型,实现的接口擦除,使用Object
class Service03<T> implements UserService{
public void add(Object t){}}
-
实现类是泛型,实现的接口泛型,泛型相等
class Service04<U> implements UserService<U>{
public void add(U t){}}
-
错误:实现类擦除,接口泛型
public interface UserService<T>{
void add(T t);
}
//声明实现类,实现的接口必须指定"具体的类型"
class Service01 implements UserService<String>{
public void add(String t){
}
}
//实现类和接口同时擦除(不写),使用Object
class Service02 implements UserService{
public void add(Object t){
}
}
//实现类是泛型,实现的接口擦除,使用Object
class Service03<T> implements UserService{
private T value;
public void add(Object t){
}
}
//实现类是泛型,实现的接口泛型,泛型相等
class Service04<U> implements UserService<U>{
public void add(U t){
}
}
class Service05<X,Y,Z> implements UserService<Y>{
public void add(Y t){
}
}
//错误:实现类擦除,接口泛型
/*
class Service06 implements UserService<Y>{
public void add(Y t){
}
}
*/