Javabean的概念(了解)
Java语言的命名,最早是Oak(橡树),因为有品牌注册该商标,他们又另外取名字。在喝咖啡时,想到用“爪哇岛”的咖啡来源地作为新语言的名字,就是Java。
因此Java中就有很多名称和“豆bean”有关。
Java类,可以称为Javabean。
但是很多时候,在平时的文章或者聊天时(特别是中国环境下),我们把Javabean的范围又缩小了,不是代码所有Java类,
而是特指哪些存储对象的基本属性的类,例如:学生类、商品类、订单类。像这些类通过都是用来表示数据的,即和数据库中的表对应。
这种类,通常有这些要求:
(1)习惯放到bean包中,有时候bean包又称为vo,pojo,do等
(2)这种中一般都是public的
(3)属性都是私有化的
(4)有标准的get/set
(5)有无参构造
(6)有toString方法
包装类型
1、什么是包装类,为什么要用包装类?
(1)Java是面向对象的语言,在Java中设计的很多语法或API,都是针对“对象”(引用数据类型)来设计的,
比如:后面的<泛型>,集合容器,等都只针对对象,不支持基本数据类型。
(2)Java中又保留了C语言的8种基本数据类型和void,所以Java是不“纯”的面向对象语言。
因为8种基本数据类型和void,有相当的背景基础,比如:有丰富的运算符的支持,有很多C库底层兼容,
并且每一种基本数据类型都有固定的宽度....等特点,使得Java就直接保留了这些类型,不用重头开始设计了。
Java发明的时候,C语言已经很成熟了,而且使用非常广泛,所以Java就借鉴C语言的一些语法或类型等。
Java一开始被人戏称为“C++--”,在C的基础上加上一些东西(对象),去掉一些东西(指针)。
(3)而且Java程序中,大量的数据仍然需要用基本数据类型来表示的。为了兼容Java的面向对象语法和基本数据类型,
Java提供了一套API,我们称为包装类。即Java为每一种基本数据类型和void都定制了一个对应的引用数据类型。
基本数据类型 包装类(java.lang包)
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
void Void
总结来说:包装类是基本数据类型与面向对象语法之间的桥梁,是一个包装。
2、如何使用包装类?
JDK1.5之前,我们需要使用包装类来包装基本数据类型的数据,必须手动装箱。即手动new对象。
JDK1.5之后,我们需要使用包装类来包装基本数据类型的数据,支持自动装箱。即不用手动new对象。
包装类的对象,就和Java其他对象一样,就可以调用方法等。
3、有时候,需要把包装类的对象,转为基本数据类型的数据,这个过程称为“拆箱”。
例如:需要使用运算符进行计算时。
JDK1.5之前,必须手动拆箱。调用包装类对象的value()方法等,把数据拿出来。
JDK1.5之后,支持自动拆箱。
装箱:把基本数据类型->包装类对象
拆箱:把包装类对象->基本数据类型
public class TestWrapper {
public static void main(String[] args) {
int a = 1;//基本数据类型
Integer objA = new Integer(a);//包装类对象,把基本数据类型的a包装为一个对象 手动装箱
//Object obj1 = a;//JDK1.5之前是错误的,因为a是基本数据类型,是不能赋值给Object类型的变量的
Object obj2 = objA;//可以的,因为objA是引用数据类型,可以赋值给给Object类型的变量的
System.out.println("-----------------------------------");
int b = 1;
Integer objB = a;//包装类对象,把基本数据类型的a包装为一个对象 自动装箱
Object obj3 = b;//JDK1.5之后是可以,因为b被自动装箱为Integer对象
System.out.println(obj3.getClass());//class java.lang.Integer
System.out.println("-----------------------------------");
//JDK1.5之前
Integer x = new Integer(1); //手动装箱
Integer y = new Integer(2); //手动装箱
System.out.println("求和:" + (x.intValue() + y.intValue())); //手动拆箱
System.out.println("比较大小:" + (x.intValue() < y.intValue()));//手动拆箱
System.out.println("-----------------------------------");
//JDK1.5之后
Integer m = 1;//自动装箱
Integer n = 2;//自动装箱
System.out.println("求和:" + (m + n)); //自动拆箱
System.out.println("比较大小:" + (m < n));//自动拆箱
}
4、包装类的其他用途
(1)实现基本数据类型与字符串之间的转换
A:把基本数据类型转为字符串很简单,直接拼接字符串就可以了
int a = 1;
String str = a + "";
B:把字符串转为基本数据类型,就需要用包装类来辅助
String str = "123";
int num = str;//错误的
int num = (int)str;//错误的
int num = Integer.parseInt(str); //可以
应用场景,从命令行参数接收的数据,Web页面接收的数据等,无论是什么类型,都是按照字符串接收的。
字符串-->int Integer.parseInt(字符串)
字符串-->double Double.parseDouble(字符串)
字符串-->long Long.parseLong(字符串)
字符串-->boolean Boolean.parseBoolean(字符串)
字符串-->char 字符串.charAt(0)
(2)获取数据类型的最大最小值
包装类.MAX_VALUE
包装类.MIN_VALUE
(3)单字符转大小写
Character.toUpperCase(letter)转大写
Character.toLowerCase(letter)转小写
(4)比较两个基本数据的值,特别是double类型
因为double类型的数据是不精确的,所以使用>,<等比较可能会有误差,一般开发中推荐使用 包装类的compare方法等方式比较。
(5)包装类中还有其他的一些方法,这里没有一一列举,可以自己看API。
public class TestWrapperAPI {
//在运行这个main方法时,传入什么类型的命令行参数,都是放到了String[] args数组中
//例如:从命令行参数接收两个整数,求和
public static void main(String[] args) {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
System.out.println("a+b=" + (a+b));
System.out.println("----------------------");
// 获取int的最大最小值
System.out.println("int的最大值:" + Integer.MAX_VALUE);//2147483647
System.out.println("int的最小值:" + Integer.MIN_VALUE);//-2147483648
System.out.println("----------------------");
char letter = 'a';
//转大写
System.out.println((char)(letter-32));
System.out.println(Character.toUpperCase(letter));
System.out.println("----------------------");
double d1 = 1.4;
double d2 = 1.2;
//Double.compare(d1, d2)方法调用会返回3种结果,分别是正、负、0
int result = Double.compare(d1, d2);
if (result == 0) {
System.out.println("d1=d2");
}else if(result>0){
System.out.println("d1>d2");
}else{
System.out.println("d1<d2");
}
}
}
5、包装类对象的缓存问题(或者说是常量对象问题)
(1)缓存对象范围
Byte,Short,Integer,Long这些整数的包装类型,会有缓存对象(常量对象):[-128,127]
因为这些范围的数字在程序开发中最常用。
Float和Double,没有缓存对象。
Character的缓存对象范围是[0,127]
Boolean类型的缓存对象:true,false
(2)什么时候会启用缓存对象
自动装箱和valueOf方法创建的包装类对象,并且在缓存范围的,就用缓存对象。
其他的不用缓存对象,例如手动new,超过缓存范围的。
(3)讲解缓存对象的作用
A:面试题
B:开发中尽量使用自动装箱和valueOf方法,这样的话,如果是缓存对象范围内的数据,就共享同一个常量对象,可以节省内存。
要是每次new的话,就占太多内存,增加GC的负担。
public class TestCache {
public static void main(String[] args) {
int a = 1;
int b = 1;
System.out.println(a == b);//true
Integer obj1 = 1; //自动装箱
Integer obj2 = 1; //自动装箱
System.out.println(obj1 == obj2);//true 比较对象的地址 用缓存对象,两个值一样的包装类对象,是同一个
System.out.println(obj1.equals(obj2));//true 如果重写比较对象的内容值,如果没有重写,也是比较地址
System.out.println("-------------------------------");
int x = 128;
int y = 128;
System.out.println(x == y);//true
Integer obj3 = 128; //自动装箱
Integer obj4 = 128; //自动装箱
System.out.println(obj3 == obj4);//false 比较对象的地址 没有用缓存对象,超过范围了,新new的
System.out.println(obj3.equals(obj4));//true Integer重写了Object的equals方法
System.out.println("-------------------------------");
Integer obj5 = new Integer(1);
Integer obj6 = new Integer(1);
System.out.println(obj5 == obj6);//false 没有用缓存对象,是新new的
System.out.println(obj5.equals(obj6));//true
System.out.println("-------------------------------");
Integer obj7 = Integer.valueOf(1);
Integer obj8 = Integer.valueOf(1);
System.out.println(obj7 == obj8);//true 用缓存对象,两个值一样的包装类对象,是同一个
System.out.println(obj7.equals(obj8));//true
}
}
6、包装类的特点
(1)包装类与基本数据类型进行运算时,会自动拆箱。
包装类与包装类进行 ==和!=、=以外的运算(<,>等)时,也会自动拆箱处理。
包装类与包装类进行 ==和!=、=的运算时,不会自动拆箱,那么要求 两边的类型必须一致。
(2)包装类与基本数据类型的自动装箱与拆箱,只在自己对应的类型之间发生
int<--->Integer
double<---->Double
....
(3)包装类对象是不可变对象
包装类对象的修改,会产生新对象。
public class TestWrapperExam {
public static void main(String[] args) {
Integer obj1 = 130;
int i = 130;
System.out.println(obj1 == i); // true obj1是引用数据类型,i是基本数据类型
//问题?是吧obj1对象自动拆为基本数据类型 还是把i自动装为包装类的对象比较?
//结果可以看出是拆箱为基本数据类型做比较
Double d = 1.2;
int j = 1;
System.out.println(d < j);//false
//d是引用数据类型,j是基本数据类型,怎么处理的?
//(1)先把d拆箱为基本数据类型double
//(2)再把int自动类型提升为double
Integer m = 1;
Double n = 1.1;
System.out.println(m < n);//m和n都是引用数据类型
//(1)先将m自动拆箱为int,n自动拆为double(2)然后int自动类型提升为double
//System.out.println(m == n);//报错 因为==本身是支持引用数据类型,如果==双边都是引用数据类型,那么就不会自动拆箱
//就按照引用数据类型处理,m和n之间是不同的,并且没有父子类关系的类型,是无法比较的
System.out.println("-------------------------");
Double d1 = 11.0; //Double与double之间可以自动装箱
Integer k = 15;//Integer与int之间可以自动装箱
// Double d2 = 15;//错误 因为左边是Double,右边是int类型,它俩之间不会直接发生自动装箱
System.out.println("-------------------------");
int num = 1;
Integer obj = 1;
String str = "java";
MyData myData = new MyData();
myData.a = 1;
MyData data = new MyData();
data.a = 1;
change(num,obj,str,myData,data);
System.out.println("num=" + num);//1
System.out.println("obj=" + obj);//1
System.out.println("str=" + str);//java
System.out.println("myData.a = " + myData.a);//2
System.out.println("data.a = " + data.a);//1
}
/*
考点:方法的参数传递机制
基本数据类型:形参修改和实参无关,例如:int
引用数据类型:形参修改了成员变量,和实参有关,例如:MyData
另外,引用数据类型的形参如果指向了新对象,也和实参无关,例如:j,s,d
*/
public static void change(int i, Integer j, String s, MyData m, MyData d){
i++;
j++; //j是包装类型,它的修改会产生新对象,相当于 j = new Integer(j+1);
s+="hello";//s是字符串,也是不可变对象类型,修改也会产生新对象,相当于 s = new String(s + "hello");
m.a ++;
d = new MyData();//d直接指向对象,和实参无关
d.a=3;
}
}
class MyData{
int a;
}