陕西旭泽建设有限公司网站seo关键词是什么意思
学习目标
- 掌握8个包装类型
- 掌握自动拆箱和自动装箱
- 了解Math
- 了解Object
- 了解Class
1.包装类
1.1. 什么是包装类
● 在Java中万事万物皆对象,但是基本数据类型的值就不是对象,那感觉就是这8个基本数据类型就很另类了;
● 因此为了让基本数据类型也具有对象的性质,JDK中定义了8个引用类型与前面所讲的8个基本数据类型相对应,而这8个引用类型都称之为包装类型;这8个类 都定义在java.lang包中,因此使用的时候也不需要显示导入;
● 包装类中定义了很多方法,静态或者实例的方法,丰富了对基本数据类型的操作;
● 之所以现在要讲包装类型,不仅是因为它们是常用类,而且 在后面要讲的集合的那一章里面,集合中是只能放对象而不能放基本数据类型的值的;因此必须要知道每个基本数据类型其所对应的包装类型;
● 这8个包装类的名称 除了 Integer Character名字不一样之外,其他都是 基本数据类型名称的首字母大写;
实际开发中, 需要从数据库中对接数据, 此时有可能对接null值, 且数据库中的数据存在数据类型区分, 所以无法存储null
的基本类型不能应对该需求场景
● 简单对比基本数据类型与包装类型
● 基本数据类型 与包装类作用一致的。
● 为什么要提供与基本数据类型作用一致的包装类?
1. java是一门面向对象的语言。不能根据基本数据类型创建对象 不太符合面向对象的思想。
2. 丰富基本数据类型的操作 提供了8个包装类型。 包含一些属性/方法、创建对象、
3. 学习集合。是一个容器。存储引用数据类型的数据。
● 基本数据类型 VS 包装类型?
● 相同点: 代表具体的一个数据 作用是一致的。
● 不同点: 一个是类(属性/方法、创建对象) 一个是基本数据类型
基本数据类型 | 默认值 | 包装类型 | 默认值 |
---|---|---|---|
byte | 0 | Byte | null |
short | 0 | Short | null |
int | 0 | Integer | null |
long | 0L | Long | null |
float | 0.0F | Float | null |
double | 0.0D | Double | null |
char | \u0000 | Character | null |
boolean | false | Boolean | null |
public static void method1() {byte by2 = 123;Byte by1;Short sh1;Integer in1;Long lo1;Float f1;Double d1;Character c1;Boolean b1;}
1.2. Integer
● 由于JDK存在8个包装类型,而且特征都是类似的。
● 因此我们在学习的时候以Integer以及Character为例,学习所有的包装类型。
1.2.1 层级
public final class Integer extends Number implements Comparable<Integer> {}
1.2.2 常用构造
● 自从JDK9之后包装类的构造方法都不建议使用了,创建包装类对象的方式都直接使用字面量赋值。
● 所有的包装类型都是一样。
1.2.3 创建对象
private static void demo1() {//过时了 不建议使用Integer num1 = new Integer(100);//将string的数据转换成Integer对象的数据Integer num2 = new Integer("100");System.out.println(num1);System.out.println(num2);int num3 = 100;System.out.println(num3);Integer num4 = 100;
}
1.2.4 装箱与拆箱
jdk5+提供:为了简化双方的转换成本, 提供了自动封箱与自动拆箱
- 自动装箱: 基本数据类型的数据转换成包装类型的对象 包装类.valueOf(基本数据类型 变量);
- 自动拆箱: 包装类对象转换成基本类型的数据 包装类引用.xxxValue()
总结一句话就是:两者使用上没差别 可以自动转;
int n1 = 10;//自动封箱Integer i1 = n1;//自动拆箱int n2 = i1;
注意:
- 自动封箱与拆箱只能发生在相同类型之间
- 包装类型之间不存在大小关系, 其相互平级, 不能发生自动类型转换
1.2.5 整数缓存池
private static void demo3() {Integer num1 = new Integer("100");Integer num2 = new Integer(100);System.out.println(num1);System.out.println(num2);System.out.println("(num1==num2):" + (num1 == num2));//false//整数缓存池-----> 数组里面存储的整数 Integer (-128-127) 256Integer num3 = Integer.valueOf(100);//基本数据转包装类对象 自动装箱 底层: Integer.valueOf()System.out.println("(num1==num3):" + (num1 == num3));//falseInteger num4 = 100;System.out.println("(num4==num3):" + (num4 == num3));//true 一块内存 newInteger num5 = 200;Integer num6 = 200;System.out.println("(num5==num6):" + (num5 == num6));//false}
● 整数缓存池。IntegerCache.cache[] -128-127之间的数字. 256个对象 new 256次
● 假如Integer num1 = 100; Integer num2 = 100; Integer num3 = 100; Integer num4 = 100; 其实内存中只有1个Integer对象。
● 优势: 提高资源的使用率 多次使用1个对象。避免内存的过渡浪费
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);
}private static class IntegerCache {static final int low = -128;static final int high;static final Integer[] cache;//存储都是Integer对象static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}
}
哪些包装类中具备整数缓存池思想?
- Integer-----> IntegerCache.cache Integer[] cache -128-127
- Byte-----> ByteCache.cache Byte[] cache -128-127
- Short-----> ShortCache.cache Short[] cache -128-127
- Long-----> LongCache.cache Long[] cache -128-127
- Character----> CharacterCache.cache Character[] cache 0-127 128 ASCII
1.2.6 其它方法
public static void method2() {
//此赋值方式和String非常相似,注意in1,in2都是对象,都是引用
//in1和in2中所存储的依然的堆空间的某块内存的起始地址值
Integer in1 = 66;
Integer in2 = 999;
//静态的成员变量 代表此类型的表叔范围
System.out.println(Integer.MIN_VALUE);
System.out.println(Integer.MAX_VALUE);
//静态方法parseInt() 把字符串转换为int类型 如果出现非数字的字符则会报异常 NumberFormatException 例如"abc";
int a1 = Integer.parseInt(“123”);
//静态方法valueOf() 功能是把字符串转换为其所对应的Integer对象 同样的如果出现非数字的字符则会报异常 NumberFormatException 例如"abc";
Integer in3 = Integer.valueOf(“123”);
// compareTo实例方法用于比较两个Integer对象的大小,返回值只有三种情况: 1表示第一个数大 0表示两个数相等
System.out.println("compareTo: " + in2.compareTo(1999));
System.out.println("parse: " + a1);
System.out.println(in3);
}
private static void demo6() {//Integer其他功能方法Integer num1 = 100;//1.Object.hashcode()获得对象的hash值System.out.println(num1.hashCode());//与对象的数据是一致的//2.与其他类型的转换float value = num1.floatValue();//3.运算System.out.println(Integer.sum(10, 20));System.out.println(Integer.max(10, 1));System.out.println(Integer.min(10, 1));System.out.println(Integer.toHexString(1000));//将10进制的整型的数据转换成无符号16进制的字符串//4.String与整型之间相互转换int num = 100;//int 转 String +System.out.println(num + "");System.out.println(String.valueOf(num));Integer num2 = 200;System.out.println(num2.toString());System.out.println(num2 + "");System.out.println(String.valueOf(num2));System.out.println("-------------------------");//String转intString str = "1234";//转10进制/* Integer i = new Integer(str);System.out.println(Integer.valueOf(str));System.out.println(Integer.valueOf(str, 10));*///将指定的字符串数据 转换成指定进制的数值// 2 0 1// 8 0-7// 10 0-9// 16 0-F// 36 0-Zint anInt = Integer.parseInt(str);System.out.println(anInt);System.out.println(Character.MIN_RADIX);System.out.println(Character.MAX_RADIX);}
1.3 Character
了解里面常用的方法即可。
public static void method6() {// 静态方法System.out.println(Character.toUpperCase('a'));System.out.println(Character.toLowerCase('A'));Character character = 'a';Character character1 = Character.valueOf('a');char[] chars = {'2', 'a', 'A'};for (int i = 0; i < chars.length; i++) {System.out.print(chars[i]);System.out.println(Character.isDigit(chars[i]) ? "是数字字符" : "不是数字字符");System.out.println(Character.isLetter(chars[i]) ? " isLetter " : " not letter");System.out.println(Character.isUpperCase(chars[i]) ? " isUpper " : " not Upper");System.out.println(Character.isLowerCase(chars[i]) ? " isLower " : " not lower");}int digit(char ch, int radix) 将字符转换成指定进制的数字int result = Character.digit('Z', 36);System.out.println(result);//-1
}
1.4 值不可变性
● 8个包装类数据是不可变的,其对象也都是不可变的对象;
● 原因都是其内部用来存储值的成员变量都是使用final修饰的,一旦赋值不可改变。
/*** 2,Integer 包装类型都是 是不可变的对象 每次重新赋值 都会有新的对象*/public static void method3() {//如下代码 是有2个字符串对象 而str只是个引用而已,引用中存储的是地址
// String str = "abc";
// str="java";//同样的in1也是引用类型 所有in1中存储的也是地址。下面的代码中有两个Integer对象;Integer in1 = 127;in1 = 128;}
包装类内部用于存储值的成员变量源码
/*** The value of the {@code Integer}.** @serial*/private final int value;
1.5 进制与位运算
程序中使用的进制的表示
/*** 进制 * 二进制(逢2进1) 以0b/0B 打头* 八进制(逢8进1) 以数字0打头* 十进制(逢10进1)* 十六进制(逢16进1 A-10 b-11 c-12 d-13 e-14 f-15)* 0x或者0X 16进制的1位相当于二进制的4位*/public static void method7() {int a = 012; // 0000 1010System.out.println("八进制 0: " + a);int b = 0Xaf; // 15+10*16System.out.println("16进制: " + b);int c = 0b10101111;System.out.println("2进制: " + c);}
位运算: 左移与右移
/*** << 左移动相当于乘2的指数值 >>向右移动 相当于除2的指数值*/public static void method8() {// 0011 1100System.out.println(3 << 2); // 3*2^2// 1010 0010System.out.println(10 >> 2); // 10/2^2}
逻辑符号用于数值运算
● &表示两边都为1 结果才是1
● |表示两边只要有一个是1 结果就是1
/*** & |*/public static void method9() {/*** 1111* 1010 &表示上下都为1才是1 |是只要有一个为1就是1* ------------* 1010*/System.out.println(15 & 10);System.out.println(15 | 0);}
1.6 使用场景
//使用场景
//在以后类中 属性/形参/返回值类型 建议使用包装类型维护
public class UserInfo {//private int id;//0//private Integer id;//null//public double zengZhangLv;//public Double zengZhangLv;//增长率 null%//增长率 0.0% 由于某些原因忘记赋值或者程序报错,对于基本类型有默认值,比如0.0 //在这种情况下 可能会认为0.0% 也是ok的数据。public Integer demo(int num){//局部变量 建议使用基本数据类型//形参与返回值类型建议使用包装类型 可以结合null值进行提前预判 规避一些不正常的现象产生。//如果真的不想用 其实影响也不是很大。我们了解这种情况即可。return null;}
}
2.Math
● Math单词表示数学。因此Math类内部提供的都是和数学运算相关的方法;
● Math类内部所有的方法都是静态方法,都是功能性方法;
/*** Math类的常用方法* 数学运算相关方法*/public static void method1() {System.out.println("绝对值:" + Math.abs(-32));System.out.println(Math.PI);System.out.println("次方: " + Math.pow(12.5, 2));System.out.println("开根号: " + Math.sqrt(16));System.out.println("max: " + Math.max(16, 10));System.out.println("min: " + Math.min(16, 10));System.out.println("[0,1) 浮点数: " + Math.random());// 四舍五入值System.out.println(Math.round(5.5));// ceil 向上取整 取最小System.out.println(Math.ceil(5.3));// floor 向下取整 取最大System.out.println(Math.floor(5.3));//+ - *System.out.println(Math.addExact(10, 20));System.out.println(Math.subtractExact(10, 20));System.out.println(Math.multiplyExact(10, 20));}
3.Object
超级父类。需要了解Object类中的每个方法。
3.1 常用方法
方法 | 作用 |
---|---|
String toString() | 返回对象的字符串表示形式。 |
protected Object clone(); | 创建并返回此对象的副本 |
boolean equals(Object obj) | 比较2个对象是否相等 |
Class<?> getClass() | 返回此 Object的运行时类。获得当前正在运行的类或者接口的class类对象。 |
int hashCode() | 返回对象的哈希码值 |
void notify() | 唤醒正在此对象监视器上等待的单个线程 |
void notifyAll() | 唤醒等待此对象监视器的所有线程。 |
void wait() | 当前线程等待 |
void wait(long timeoutMillis) | 时间内等待 |
void wait(long timeoutMillis, int nanos) | — |
3.2 toString
● 面向对象本质: 使用对象封装数据 使用类管理代码
● 打印输出对象,就是想看到属性的数据。底层默认执行toString的方法,打印输出的16进制的hash值
public String toString() {return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserInfo /*extends Object*/{private Integer id;private String name;private Integer age;// @Override
// public String toString() {
// return "UserInfo{" +
// "id=" + id +
// ", name='" + name + '\'' +
// ", age=" + age +
// '}';
// }
}
public static void main(String[] args) {UserInfo userInfo1 = new UserInfo(1,"张三",18);UserInfo userInfo2 = new UserInfo(1,"张三",18);//打印输出引用类型对象 底层默认Object.toString()System.out.println(userInfo1.toString());System.out.println(userInfo2);
}
3.3 equals+hashcode
为什么重写equals+hashcode?
在正常生活中 我们会认为2个对象 是一个对象。 true
比较2个对象是否一致/相等
1.比较运算符: == 内存地址值
2.比较对象: equals+hashcode
- 在jvm规范: 2个对象的hashcode不同 这2个对象就是不等的。
- 2个对象的hashcode相同 不能直接认为2个对象相同的 hash算法有弊端。hash会经常出现碰撞。
- 2个对象equals 结果true 这2个对象的hash必须相同。
- jvm硬性规定: 重写equals 也必须重写hashcode。equals+hashcode规则一致的。
需求: 比较2个对象是否一致/相等
public boolean equals(Object obj) {return (this == obj);
}public native int hashCode();
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserInfo {private Integer id;private String name;private Integer age;
}
public static void main(String[] args) {UserInfo userInfo1 = new UserInfo(1, "张三", 18);UserInfo userInfo2 = new UserInfo(2, "张三", 20);//打印输出引用类型对象 底层默认Object.toString()System.out.println(userInfo1.toString());System.out.println(userInfo2);//System.out.println("(userInfo1==userInfo2):" + (userInfo1 == userInfo2));System.out.println("(userInfo1.equals(userInfo2)):" + userInfo1.equals(userInfo2));int code1 = userInfo1.hashCode();int code2 = userInfo2.hashCode();System.out.println(code1);System.out.println(code2);String s1 = "Ma";String s2 = "NB";System.out.println(s1.hashCode());System.out.println(s2.hashCode());}
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
//@EqualsAndHashCode //类中所有的属性都参与
public class UserInfo /*extends Object*/ {private Integer id;private String name;private Integer age;//2个对象相等的规则: id name age 都相同的时候@Overridepublic boolean equals(Object obj) {//this objif (obj == null) return false;if (!(obj instanceof UserInfo)) return false;UserInfo userInfo = (UserInfo) obj;returnObjects.equals(name, userInfo.name);}//重写父类的hashcode@Overridepublic int hashCode() {return Objects.hash(name);}
}
3.4 clone
克隆对象。属于创建对象的一种方式
Object里面的clone()方法
protected native Object clone() throws CloneNotSupportedException;
@Setter
@Getter
@Accessors(fluent = true)
@ToString
public class GirlFriend extends Object implements Cloneable {//Cloneable是一个标记接口。类实现Cloneable接口 代表这个类对象可以被克隆的。private Integer id;private String name;private int age;private String[] hobby;//思考:复制的是数据还是内存地址值?//基本的数据类型: 数据//引用数据类型: 内存地址值//值的传递@Overridepublic GirlFriend clone() {GirlFriend clone = null;try {clone = (GirlFriend) super.clone();//对属性执行遍历式克隆//clone.hobby(Arrays.copyOf(this.hobby,hobby.length));clone.hobby(this.hobby.clone());} catch (CloneNotSupportedException e) {System.out.println("类必须实现Cloneable接口");e.printStackTrace();}return clone;}public GirlFriend() {System.out.println("无参构造...........");}
}
浅克隆与深克隆
1.浅克隆(浅复制/copy)
- 是否真的可以克隆成功? 为什么会有CloneNotSupportedException?
- 代码可能会报错。 类一定要实现Cloneable标记接口。
- 克隆的对象与源对象是否是同一个对象?
- 不是同一个
- 克隆的对象是否执行了构造方法?
- 没有执行构造方法。jvm底层调用C创建新的对象
- 克隆对象的属性的数据是否有值? 数据是否与原对象的属性的数据是一致的?
- 有值 与源对象的数据是一致的。
5.修改了一个对象的属性的数据 是否会影响另外一个对象的数据?- 在浅克隆的操作下 修改一个对象的数据 可能会影响另外一个对象的数据
- 属性: 基本数据类型 没有任何影响 复制的是数据
- 包装类型+String—> 值不可变 修改一个对象 值不变的
- 其他的引用数据类型 数据就会发生改变 数组,自定义的类(浅克隆的弊端)
- 深克隆/序列化-----> 解决浅克隆的问题
- 需求: 修改一个对象的数据 不要影响另外一个对象的数据、
- 操作: 对象在哪里克隆的 就在那里修改
public static void main(String[] args) {String[] hobby = new String[]{"大提琴", "show", "sing"};GirlFriend girlFriend1 = new GirlFriend().id(1).name("欧阳娜娜").age(18).hobby(hobby);//克隆一个女友对象 Object.clone();//girlFriend1.clone//1.在其他类中 无法访问clone protected//2.在父类clone方法中 返回值类Object----> GirlFriend//建议在子类中重写父类的方法GirlFriend cloneGirlFriend = girlFriend1.clone();System.out.println("girlFriend1:" + girlFriend1);System.out.println("cloneGirlFriend:" + cloneGirlFriend);cloneGirlFriend.id(2);cloneGirlFriend.name("欧阳娜娜2");cloneGirlFriend.age(20);cloneGirlFriend.hobby()[0] = "小提琴";System.out.println("---------------------------");System.out.println("girlFriend1:" + girlFriend1);System.out.println("cloneGirlFriend:" + cloneGirlFriend);}
● 克隆对单例是否有影响?
public class Cat implements Cloneable {private Cat() {}private final static Cat instance = new Cat();public static Cat getInstance() {return instance;}@Overridepublic Cat clone() throws CloneNotSupportedException {return this;}
}
class Test{public static void main(String[] args) throws CloneNotSupportedException {/*for (int i = 0; i < 100; i++) {System.out.println(Cat.getInstance());}*///克隆是否可以打破单例? 可以打破单例Cat cat1 = Cat.getInstance();Cat cloneCat = cat1.clone();System.out.println(cat1);System.out.println(cloneCat);System.out.println(cat1==cloneCat);//有且只有1个cat对象}
}
3.5 finalize
final VS finally VS finalize?1. final 修饰符类 变量 方法2. finally异常处理机制的关键字。 try....catch...finally try...finally释放物理资源/释放监视器释放物理资源: jdk1.7+ 建议使用try...with....reources 省略finally代码块3.finalize是Object.finalize(); 满足于GC回收无用引用关联的对象,释放内存。不需要手动调用。 目前方法过时了。
4.Class
● Class类代表当前程序中正在运行的类或者接口的Class类对象。
● Class类是反射机制的基础。
● 目前我们只先了解获得Class类对象的3种方式,与反射相关的技术点我们到后面学习。
● 在开发中,本质上下面3种方式,我们都可以使用。
private static void demo4() {//需求: 获得UserInfo.class在运行期间的Class类对象//1. Class getClass() 不推荐 与对象的耦合度太高了 不太建议UserInfo userInfo = new UserInfo();Class userInfoClass = userInfo.getClass();//userInfoClass就等价于获得UserInfo.classSystem.out.println(userInfoClass.toString());//class com.java .lang.UserInfoSystem.out.println(userInfoClass.getName());System.out.println(userInfoClass.getSimpleName());//2.使用静态属性 class 类型的名称.class 推荐使用的 在本项目内访问本项目内其他的类或者接口//任意一个类型里面 都有一个静态属性 classClass aClass = int.class;Class userInfoClass = UserInfo.class;Class cloneableClass = Cloneable.class;System.out.println(aClass);System.out.println(userInfoClass.toString());System.out.println(userInfoClass.getName());System.out.println(userInfoClass.getSimpleName());//3. Class.forName("类/接口的全限定名称"); 类/接口的路径 包名+类名 com.java .lang.UserInfo//推荐 加载第3方类库资源里面的类或者接口 (jar) try {Class aClass = Class.forName("com.java .lang.UserInfo");System.out.println(aClass.getName());System.out.println(aClass.getSimpleName());} catch (ClassNotFoundException e) {e.printStackTrace();}
}