文章目录
Object类的学习
在java,所有的类都是Object类子类
Object类是所有类的父类
-----Object.java
getClass(); // 获取字节码文件
hashcode(); // 对象的hashcode值
equals(); // 判断两个对象是否相等,使用的地址判断
finalize(); // 垃圾回收前自动执行的该方法
For example
package om.openlab.da14.object;
public class Test {
public static void main(String[] args) {
User u = new User();
System.out.println(u.getClass()); // class om.openlab.da14.object.User
System.out.println(u.hashCode()); // 2083562754
}
}
class User {
}
native关键字
native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中
✨hashcode()
如果两个对象是同一个对象(地址相同),hashcode值肯定一样,
如果两个对象hashcode值相同,不一定是同一个对象
OpenJDK:提供了五种hashcode算法,其中有一种,直接返回内存地址
就是内存地址hash值,这句话不算错,但是不一定准确
注意:
如果两个对象的equals
比较相等,hashcode
肯定相等
如果两个对象的hashcode
相等,equals
不一定相等
final、finally、finalize()三者的区别
final
1、final修饰的class,代表不可以继承扩展。
2、final的方法也是不可以重写的。
3、final修饰的变量是不可以修改的。这里所谓的不可修改对于基本类型来来,的确是不可以修改。而对于引用类型来说,只能说不能重新赋值。也就是不能改变引用地址。但是作为引用类型,它内部所包含的内容如果不是final则可以随意修改
finally
提到finally,那么try-catch就逃不掉了。finally 则是Java保证重点代码一定要被执行的一种机制。最常用的地方:通过try-catch-finally来进行类似资源释放、保证解锁等动作
finalize
设计之初的作用就是:在CG要回收某个对象时,让这个对象有底气的大喊一声:“报告,我还能再抢救一下!”。但是也正是因为如此,JVM要对它进行额外处理。finalize也就成为了CG回收的阻碍者,也就会导致这个对象经过多个垃圾收集周期才能被回收。
对象拷贝
此处可以参考博客:
1.ava如何复制对象
2.java引用拷贝,对象浅拷贝,对象深拷贝
引用传递:
对象是没有拷贝,是同一个对象,拷贝的是栈内存(地址)
在java中,如果某个类需要调用Object的clone完成对象的拷贝,必须让该类实现
在java中,如果一个类要实现clone方法,必须要实现一个接口(Cloneable)
在java中,存在了一类接口,里面没有任何代码,标注接口!!!
浅拷贝:
Object类,提供的`clone`方法就是浅拷贝(对象)
在进行对象拷贝时候,仅仅完成了对象的第一层拷贝,如果该对象存在着子对象,则
不会拷贝子对象
深拷贝:
递归拷贝,会把所有的对象全部分离
1、让子对象也实现Cloneable接口,在父对象进行拷贝是,子对象也同时拷贝
2、通过序列化对象和反序列化来实现深拷贝
引用传递
package om.openlab.da14.copy;
public class Test {
public static void main(String[] args) {
User user2 = new User();
user2.setUsername("第一");
// user2的地址传递到user3中,对象没有拷贝,拷贝的是栈地址
User user3 = user2;
System.out.println(user2); // User{username='第一'}
System.out.println(user3); // User{username='第一'}
user2.setUsername("第二");
System.out.println(user2); // User{username='第二'}
System.out.println(user3); // User{username='第二'}
}
}
class User {
private String username;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
浅拷贝
package om.openlab.da14.copy;
public class User implements Cloneable{ // 实现Cloneable接口
private String username;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
-----
package om.openlab.da14.copy;
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
User user2 = new User();
user2.setUsername("第一");
User user4 = (User) user2.clone();
System.out.println(user2 == user4); // false
user4.setUsername("第二");
System.out.println(user2); // User{username='第一'}
System.out.println(user4); // User{username='第二'}
}
}
基本类型包装类
想要知道 Java为什么需要包装类型 可以参考下面这篇博客
Java中有了基本数据类型,为什么还需要包装类型
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | CHaracter |
boolean | Boolean |
Integer类的概述和使用
Integer:包装一个对象中的原始类型int的值
方法名 | 说明 |
---|---|
public Integer(int value) | 根据int 值创建Integer 对象(过时) |
public Integer(String s) | 根据String 值创建Integer 对象(过时) |
public static Integer valueOf(int i) | 返回表示指定的int 值的Integer 实例 |
public static Integer valueOf(String s) | 返回一个保存指定值的Integer 对象String |
int 和 String的相互转换
基本类型包装类的最常见操作就是:用于基本类型和字符串之间的相互转换
1.int转换为String
public static String valueOf(inti)
:返回int 参数的字符串表示形式。该方法是String类中的方法
2.String转换为int
public static int parseInt(Strings)
:将字符串解析为int类型。该方法是Integer类中的方法
For example
package om.openlab.da14.packing;
public class InterDemo02 {
public static void main(String[] args) {
// int -> String
int number = 100;
// 方式1
String s1 = number + "";
System.out.println(s1);
// 方式2
// public static String valueOf(int i)
String s2 = String.valueOf(number);
System.out.println(s2);
System.out.println("--------");
// String -> int
String s = "100";
// 方式一
// String -> Integer -> int
Integer i = Integer.valueOf(s);
// public int intValue()
int x = i.intValue();
System.out.println(x);
// 方式2
// public static int parseInt(String s)
int y = Integer.parseInt(s);
System.out.println(y);
}
}
自动装箱和拆箱
装箱:把基本数据类型转换为对应的包装类类型
拆箱:把包装类类型转换为对应的基本数据类型
For example
package om.openlab.da14.packing;
public class IntegerDemo03 {
public static void main(String[] args) {
// 装箱,把基本数据类型转换为对应的包装类型
Integer i = Integer.valueOf(100);
Integer ii = 100; // Integer.valueOf(100) 自动装箱
// 拆箱,把包装类类型转换为对应的基本数据类型
// ii +=200;
// ii = ii.intValue() + 200; // ii.intValue() 这个就是拆箱
ii += 200; // 自动拆箱
System.out.println(ii);
Integer iii = null;
if (iii != null) {
iii += 300; // NullPointerException 空指针异常
}
}
}
注意:在使用包装类类型的时候,如果做操作,最好先判断是否为null
推荐:只要是对象,在使用前就必须进行不为null的判断
String类
String类在java.lang包下,所以使用的时候不需要导包
String类代表字符串,Java程序中的所有字符串文字(例如“abc”)都被实现为此类的实例也就是说,Java程序中所有的双引号字符串,都是String类的对象
字符串的特点
字符串对象只有在编译时没法确认结果才会创建新的对象
字符串不可变,它们的值在创建后不能被更改虽然String的值是不可变的,但是它们可以被共享
字符串效果上相当于字符数组(char[ ]
),但是底层原理是字节数组( byte[ ]
)
JDK8及以前是字符数组,JDK9及以后是字节数组
String构造方法
方法名 | 说明 |
---|---|
public String( ) | 创建一个空白字符串对象,不含有任何内容 |
public String(char[] chs) | 根据字符数组的内容,来创建字符串对象 |
public String(byte[ ] bys) | 根据字节数组的内容,来创建字符串对象 |
String s = “abc” ; | 直接赋值的方式创建字符串对象,内容就是abc |
For example
package om.openlab.da14.packing;
public class StringDemo {
public static void main(String[] args) {
String s1 = new String();
System.out.println("s1:"+s1);
char[] chs = {'a','b','c'};
String s2 = new String(chs);
System.out.println("s2:"+s2);
byte[] bys = {97,98,99};
String s3 = new String(bys);
System.out.println("s3:"+s3);
String s4 = "abc";
System.out.println("s4:"+s4);
}
}
字符串比较
1.==
比较字符串的地址
2.eaual()
比较字符串的内容
For example
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
字符串拼接问题:
在java,一定不要循环拼接字符串,因为会产生大量的废弃字符串(无法被gc回收,常驻内存)
StringBuilder:线程不安全(非线程安全的)
StringBuffer: 是线程安全的
字符串常量池
此处转自博客:深入理解Java String类
/**
* 运行结果为true false
*/
String s1 = "AB";
String s2 = "AB";
String s3 = new String("AB");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
java中的字符串,都保存在字符串常量池中,而且有且只有一份!!字符串是一种常量
面试题:java中的字符串常量池,JVM的什么地方?
JDK7之前,类似于字符串常量池等等常量数据都是存储方法区(Method Area),也被叫做永久代
JDK7开始去永久代,将字符串常量池等等常量数据存储到堆内里。
JDK8,元数据区(Metaspace),将1.6其他一些存储在方法区的数据,挪到了元数据区中,
字符串常量池并没有被挪回去
言外之意:java从jdk7,字符串常量池存储在heap中,jdk之前是存储在永久代中。
注意: 在编译时,已经确定的结果的字符串,不会创建对象,直接比较常量池中的值
在编译的时候,结果不确定,则会创建字符串对象
StringBuilder
String,StringBuffer与StringBuilder的区别参考博客:
String,StringBuffer与StringBuilder的区别
StringBuilder是一个可变的字符串类,我们可以把它看成是一个容器这里的可变指的是StringBuilder对象中的内容是可变的
String和StringBuilder的区别:
String:内容是不可变的
StringBuilder:内容是可变的
StringBuilder构造方法
方法名 | 说明 |
---|---|
public StringBuilder( ) | 创建一个空白可变字符串对象,不含有任何内容 |
public StringBuilder(String str) | 根据字符串的内容,来创建可变字符串对象 |
For example
package om.openlab.da14.packing;
public class StringBuilderDemo {
public static void main(String[] args) {
StringBuilder sb = new StringBuilder();
System.out.println("sb:"+sb);
System.out.println("sb.length():"+sb.length());
StringBuilder sb2 = new StringBuilder("hello");
System.out.println("sb2:"+sb2);
System.out.println("sb2.length():"+sb2.length());
}
}
StringBuilder的添加和反转方法
方法名 | 说明 |
---|---|
public StringBuilder append(任意类型) | 添加数据,并返回对象本身 |
public StringBuilder reverse( ) | 返回相反的字符序列 |
StringBuilder和 String相互转换
1.StringBuilder转换为String
public String toString()
:通过toString()
就可以实现把StringBuilder
转换为String
2.String转换为StringBuilder
public StringBuilder(String s)
:通过构造方法就可以实现把String
转换为StringBuilder