JavaSE——包||访问控制权限||toString||equals||finalize||hashCode

First Post:

Last Update:

Word Count:
4k

Read Time:
17 min

package

第一:package出现在java源文件第一行。
第二:带有包名怎么编译?javac -d . xxx.java
第三:怎么运行?java 完整类名

补充:以后说类名的时候,如果带着包名描述,表示完整类名。
如果没有带包,描述的话,表示简类名。
java.util.Scanner 完整类名。
Scanner 简类名

import

import什么时候不需要?
java.lang不需要。
同包下不需要。
其它一律都需要。

用法:
import 完整类名;
import 包名.*;

import java.util.Scanner; // 完整类名。
import java.util.*;

但import java.; 这是不允许的,因为在java语言中规定,这里的只代表某些类的名字。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com;

// 将需要的类导入。
//import com.bjpowernode.javase.chapter17.HelloWorld;
import com.bjpowernode.javase.chapter17.*;

public class Test02{
public static void main(String[] args){
/*
Test02在com包下。
HelloWorld在com.bjpowernode.javase.chapter17下。
不在同一个package下,包名可以省略吗?
不能省略。
*/
//错误: 找不到符号
/*
HelloWorld hw = new HelloWorld();
System.out.println(hw);
*/

/*
com.bjpowernode.javase.chapter17.HelloWorld hw = new com.bjpowernode.javase.chapter17.HelloWorld();
System.out.println(hw);

com.bjpowernode.javase.chapter17.HelloWorld hw2 = new com.bjpowernode.javase.chapter17.HelloWorld();
System.out.println(hw2);

com.bjpowernode.javase.chapter17.HelloWorld hw3 = new com.bjpowernode.javase.chapter17.HelloWorld();
System.out.println(hw3);
*/

HelloWorld hw1 = new HelloWorld();
System.out.println(hw1);

HelloWorld hw2 = new HelloWorld();
System.out.println(hw2);
}
}

访问控制权限

访问控制权限

1、访问控制权限都有哪些?
4个。
private 私有
public 公开
protected 受保护
默认

2、以上的4个访问控制权限:控制的范围是什么?
private 表示私有的,只能在本类中访问
public 表示公开的,在任何位置都可以访问
“默认”表示只能在本类,以及同包下访问。
protected表示只能在本类、同包、子类中访问。

    访问控制修饰符			本类			同包			子类			任意位置
    -----------------------------------------------------------------------------------------------------------------
    public				可以			可以			可以			可以
    protected			可以			可以			可以			不行
    默认				可以			可以			不行			不行
    private				可以			不行			不行			不行

范围从大到小排序:public > protected > 默认 > private

3、访问控制权限修饰符可以修饰什么?
属性(4个都能用)
方法(4个都能用)
类(public和默认能用,其它不行。)
接口(public和默认能用,其它不行。)

toString方法

以后所有类的toString()方法是需要重写的。
重写规则,越简单越明了就好。

System.out.println(引用); 这里会自动调用“引用”的toString()方法。
String类是SUN写的,toString方法已经重写了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/*
关于Object类中的toString()方法

1、源代码长什么样?
public String toString() {
return this.getClass().getName() + "@" + Integer.toHexString(hashCode());
}
源代码上toString()方法的默认实现是:
类名@对象的内存地址转换为十六进制的形式

2、SUN公司设计toString()方法的目的是什么?
toString()方法的作用是什么?
toString()方法的设计目的是:通过调用这个方法可以将一个“java对象”转换成“字符串表示形式”

3、其实SUN公司开发java语言的时候,建议所有的子类都去重写toString()方法。
toString()方法应该是一个简洁的、详实的、易阅读的.
*/
public class Test01{
public static void main(String[] args){
MyTime t1 = new MyTime(1970, 1, 1);
// 一个日期对象转换成字符串形式的话,我可能还是希望能看到具体的日期信息。
String s1 = t1.toString();

//MyTime类重写toString()方法之前
//System.out.println(s1); // MyTime@28a418fc

//MyTime类重写toString()方法之后
System.out.println(s1); // 1970年1月1日


//System.out.println(t1.toString()); //1970年1月1日

// 注意:输出引用的时候,会自动调用该引用的toString()方法。
System.out.println(t1);
}
}
class MyTime{
int year;
int month;
int day;

public MyTime(){

}

public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}

// 重写toString()方法
// 这个toString()方法怎么重写呢?
// 越简洁越好,可读性越强越好。
// 向简洁的、详实的、易阅读的方向发展
public String toString(){
//return this.year + "年" + this.month + "月" + this.day + "日";
return this.year + "/" + this.month + "/" + this.day;
}
}

equals方法

以后所有类的equals方法也需要重写,因为Object中的equals方法比较的是两个对象的内存地址,我们应该比较内容,所以需要重写

重写规则:自己定,主要看是什么和什么相等时表示两个对象相等。

基本数据类型比较实用:==
对象和对象比较:调用equals方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/*
关于Object类中的equals方法
1、equals方法的源代码
public boolean equals(Object obj) {
return (this == obj);
}
以上这个方法是Object类的默认实现。


2、SUN公司设计equals方法的目的是什么?
以后编程的过程当中,都要通过equals方法来判断两个对象是否相等。
equals方法是判断两个对象是否相等的。

3、我们需要研究一下Object类给的这个默认的equals方法够不够用!!!!
在Object类中的equals方法当中,默认采用的是“==”判断两个java对象
是否相等。而“==”判断的是两个java对象的内存地址,我们应该判断
两个java对象的内容是否相等。所以老祖宗的equals方法不够用,
需要子类重写equals。

4、判断两个java对象是否相等,不能使用“==”,因为“==”比较的是两个
对象的内存地址。
*/
public class Test02{
public static void main(String[] args){

// 判断两个基本数据类型的数据是否相等直接使用“==”就行。
int a = 100;
int b = 100;
// 这个“==”是判断a中保存的100和b中保存的100是否相等。
System.out.println(a == b); //true(相等) false(不相等)

// 判断两个java对象是否相等,我们怎么办?能直接使用“==”吗?
// 创建一个日期对象是:2008年8月8日。
MyTime t1 = new MyTime(2008, 8, 8); //MyTime t1 = 0x1234;
// 创建了一个新的日期对象,但表示的日期也是:2008年8月8日。
MyTime t2 = new MyTime(2008, 8, 8); //MyTime t2 = 0x3698;

//测试以下,比较两个对象是否相等,能不能使用“==”???
// 这里的“==”判断的是:t1中保存的对象内存地址和t2中保存的对象内存地址是否相等。
System.out.println(t1 == t2); // false

// 重写Object equals方法之前(比较的是对象内存地址)
/*
boolean flag = t1.equals(t2);
System.out.println(flag); //false
*/


// 重写Object equals方法之后(比较的是内容。)
boolean flag = t1.equals(t2);
System.out.println(flag); //true

// 再创建一个新的日期
MyTime t3 = new MyTime(2008, 8, 9);
// 两个日期不相等,就是false。
System.out.println(t1.equals(t3)); // false

// 我们这个程序有bug吗?可以运行,但是效率怎么样?低(怎么改造。)
MyTime t4 = null;
System.out.println(t1.equals(t4)); //false
}
}

class MyTime { //extends Object{
int year;
int month;
int day;

public MyTime(){

}
public MyTime(int year, int month, int day){
this.year = year;
this.month = month;
this.day = day;
}

// 默认的equals方法
/*
public boolean equals(Object obj) {
return (this == obj);
}
*/

/*
// 重写Object类的equals方法
// 怎么重写?复制粘贴。相同的返回值类型、相同的方法名、相同的形式参数列表。
// equals到底应该怎么重写?你自己定,你认为两个对象什么相等的时候表示相等,你就怎么重写。
public boolean equals(Object obj) {
// 当年相同,月相同,并且日也相同的时候,表示两个日期相同。两个对象相等。
// 获取第一个日期的年月日
int year1 = this.year;
int month1 = this.month;
int day1 = this.day;

// 获取第二个日期的年月日
//int year2 = obj.year;
//int month2 = obj.month;
//int day2 = obj.day;

if(obj instanceof MyTime){
MyTime t = (MyTime)obj;
int year2 = t.year;
int month2 = t.month;
int day2 = t.day;
if(year1 == year2 && month1 == month2 && day1 == day2){
return true;
}
}
// 程序能够执行到此处表示日期不相等。
return false;
}
*/

/*
// 改良equals方法
public boolean equals(Object obj) {
// 如果obj是空,直接返回false
if(obj == null){
return false;
}
// 如果obj不是一个MyTime,没必要比较了 ,直接返回false
if(!(obj instanceof MyTime)){
return false;
}
// 如果this和obj保存的内存地址相同,没必要比较了,直接返回true。
// 内存地址相同的时候指向的堆内存的对象肯定是同一个。
if(this == obj){
return true;
}
// 程序能够执行到此处说明什么?
// 说明obj不是null,obj是MyTime类型。
MyTime t = (MyTime)obj;
if(this.year == t.year && this.month == t.month && this.day == t.day){
return true;
}

// 程序能到这里返回false
return false;
}
*/


//再次改良。
/*
public boolean equals(Object obj) {
// 如果obj是空,直接返回false
if(obj == null){
return false;
}
// 如果obj不是一个MyTime,没必要比较了 ,直接返回false
if(!(obj instanceof MyTime)){
return false;
}
// 如果this和obj保存的内存地址相同,没必要比较了,直接返回true。
// 内存地址相同的时候指向的堆内存的对象肯定是同一个。
if(this == obj){
return true;
}
// 程序能够执行到此处说明什么?
// 说明obj不是null,obj是MyTime类型。
MyTime t = (MyTime)obj;
return this.year == t.year && this.month == t.month && this.day == t.day ;
}
*/

public boolean equals(Object obj) {
if(obj == null || !(obj instanceof MyTime)){
return false;
}
if(this == obj){
return true;
}
MyTime t = (MyTime)obj;
return this.year == t.year && this.month == t.month && this.day == t.day ;
}

}

/*
class Person{
private String idCard;
}
*/

String类重写方法:
String类是SUN编写的,所以String类的equals方法重写了。
以后判断两个字符串是否相等,最好不要使用==,要调用字符串对象的equals方法。
注意:重写equals方法的时候要彻底。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

/*
java语言当中的字符串String有没有重写toString方法,有没有重写equals方法。

总结:
1、String类已经重写了equals方法,比较两个字符串不能使用==,必须使用equals。
equals是通用的。

2、String类已经重写了toString方法。

大结论:
java中什么类型的数据可以使用“==”判断
java中基本数据类型比较是否相等,使用==

java中什么类型的数据需要使用equals判断
java中所有的引用数据类型统一使用equals方法来判断是否相等。

这是规矩。
*/
public class Test03{
public static void main(String[] args){

// 大部分情况下,采用这样的方式创建字符串对象
String s1 = "hello";
String s2 = "abc";

// 实际上String也是一个类。不属于基本数据类型。
// 既然String是一个类,那么一定存在构造方法。
String s3 = new String("Test1");
String s4 = new String("Test1");
// new两次,两个对象内存地址,s3保存的内存地址和s4保存的内存地址不同。
// == 判断的是内存地址。不是内容。
System.out.println(s3 == s4); // false

// 比较两个字符串能不能使用双等号?
// 不能,必须调用equals方法。
// String类已经重写equals方法了。
System.out.println(s3.equals(s4)); // true

// String类有没有重写toString方法呢?
String x = new String("动力节点");
// 如果String没有重写toString()方法,输出结果:java.lang.String@十六进制的地址
// 经过测试:String类已经重写了toString()方法。
System.out.println(x.toString()); //动力节点
System.out.println(x); //动力节点
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

// equals方法重写的时候要彻底。

public class Test05{
public static void main(String[] args){

// 多态(自动类型转换。)
Object o1 = new String("hello world!");
Object o2 = new User();
Object o3 = new Address();

User u1 = new User("zhangsan", new Address("北京","大兴区","11111"));
User u2 = new User("zhangsan", new Address("北京","大兴区","11111"));

System.out.println(u1.equals(u2)); // true

User u3 = new User("zhangsan", new Address("北京","朝阳区","11112"));
System.out.println(u1.equals(u3)); // false
}
}

class User{
// 用户名
String name;
// 用户的住址
Address addr;

public User(){
}
public User(String name, Address addr){
this.name = name;
this.addr = addr;
}

// 重写equals方法
// 重写规则:当一个用户的用户名和家庭住址都相同,表示同一个用户。
// 这个equals判断的是User对象和User对象是否相等。
public boolean equals(Object obj){
// 用户名和用户名相同,住址和住址相同的时候,认定是同一个用户。
if(obj == null || !(obj instanceof User)) return false;
if(this == obj) return true;

User u = (User)obj;
if(this.name.equals(u.name) && this.addr.equals(u.addr)){
return true;
}
return false;
}
}

class Address{
String city;
String street;
String zipcode;

public Address(){

}
public Address(String city,String street,String zipcode){
this.city = city;
this.street = street;
this.zipcode = zipcode;
}

// 注意:这里并没有重写equals方法。
// 这里的equals方法判断的是:Address对象和Address对象是否相等。
public boolean equals(Object obj){
if(obj == null || !(obj instanceof Address)) return false;
if(this == obj) return true;
// 怎么算是家庭住址相同呢?
// 城市相同,街道相同,邮编相同,表示相同。
Address a = (Address)obj;
if(this.city.equals(a.city)
&& this.street.equals(a.street)
&& this.zipcode.equals(a.zipcode)){
return true;
}
return false;
}
}

finalize方法(了解即可)

关于Object类中的finalize()方法。(非重点 了解即可。)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/*
关于Object类中的finalize()方法。(非重点 了解即可。)

1、在Object类中的源代码:
protected void finalize() throws Throwable { }

GC:负责调用finalize()方法。

2、finalize()方法只有一个方法体,里面没有代码,而且这个方法是protected修饰的。

3、这个方法不需要程序员手动调用,JVM的垃圾回收器负责调用这个方法。
不像equals toString,equals和toString()方法是需要你写代码调用的。
finalize()只需要重写,重写完将来自动会有程序来调用。

4、finalize()方法的执行时机:
当一个java对象即将被垃圾回收器回收的时候,垃圾回收器负责调用
finalize()方法。

5、finalize()方法实际上是SUN公司为java程序员准备的一个时机,垃圾销毁时机。
如果希望在对象销毁时机执行一段代码的话,这段代码要写到finalize()方法当中。

6、静态代码块的作用是什么?
static {
....
}
静态代码块在类加载时刻执行,并且只执行一次。
这是一个SUN准备的类加载时机。

finalize()方法同样也是SUN为程序员准备的一个时机。
这个时机是垃圾回收时机。

7、提示:
java中的垃圾回收器不是轻易启动的,
垃圾太少,或者时间没到,种种条件下,
有可能启动,也有可能不启动。
*/
public class Test06{
public static void main(String[] args){
/*
// 创建对象
Person p = new Person();

// 怎么把Person对象变成垃圾?
p = null;
*/

// 多造点垃圾
/*
for(int i = 0; i < 100000000; i++){
Person p = new Person();
p = null;
}
*/

for(int i = 0; i < 1000; i++){
Person p = new Person();
p = null;

// 有一段代码可以建议垃圾回收器启动。
if(i % 2 == 0){
System.gc(); // 建议启动垃圾回收器。(只是建议,可能不启动,也可能启动。启动的概率高了一些。)
}
}

}
}

// 项目开发中有这样的业务需求:所有对象在JVM中被释放的时候,请记录一下释放时间!!!
// 记录对象被释放的时间点,这个负责记录的代码写到哪里?
// 写到finalize()方法中。
class Person{

// 重写finalize()方法
// Person类型的对象被垃圾回收器回收的时候,垃圾回收器负责调用:p.finalize();
protected void finalize() throws Throwable {
// this代表当前对象
System.out.println(this + "即将被销毁!");
}

}

hashCode方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
hashCode方法:
在Object中的hashCode方法是怎样的?
public native int hashCode();

这个方法不是抽象方法,带有native关键字,底层调用C++程序。

hashCode()方法返回的是哈希码:
实际上就是一个java对象的内存地址,经过哈希算法,得出的一个值。
所以hashCode()方法的执行结果可以等同看做一个java对象的内存地址。
*/
public class Test07{
public static void main(String[] args){
Object o = new Object();
int hashCodeValue = o.hashCode();

// 对象内存地址经过哈希算法转换的一个数字。可以等同看做内存地址。
System.out.println(hashCodeValue); //798154996

MyClass mc = new MyClass();
int hashCodeValue2 = mc.hashCode();
System.out.println(hashCodeValue2); //1392838282

MyClass mc2 = new MyClass();
System.out.println(mc2.hashCode()); // 523429237
}
}

class MyClass
{
}