Day15
1.访问修饰符
理解:给类、方法、属性定义访问权限的关键字
注意:
1.修饰类只能使用public和默认的访问权限
2.修饰方法和属性可以使用所有的访问权限
经验:
1.属性一般使用private修饰,因为封装
2.属性或者方法如果需要被子类使用,一般使用protected修饰
3.方法如果不需要被外界使用,一般使用private修饰
4.方法一般使用public修饰
访问修饰符 | 本类 | 本包 | 其他包子类 | 其他包 |
---|---|---|---|---|
private | OK | |||
默认的 | OK | OK | ||
protected | OK | OK | OK | |
public | OK | OK | OK | OK |
public class A {
public String str = "A类的属性";
public void method(){
System.out.println(str);
}
}
public class Test01 {
public static void main(String[] args) {
A a = new A();
System.out.println(a.str);
}
}
2.Object类
概念:所有类的基类或者超类
理解:如果一个类没有明确继承的类,默认继承Object,所以说Object是所有类的祖先类
equals():
比较两个对象的内存地址是否相同
底层代码:
public boolean equals(Object obj){
return this == obj;
}
getClass():
getClass方法就是获取该类的class对象
前言:
使用到类,会把该类的class文件加载到方法区,并且在堆中创建该类的class对象
该类的class对象作为class文件的访问入口
class文件只加载1次,所以该类的class对象在内存中也只有一个
hashCode():
获取对象的hash值
注意:hash值不等于内存地址,hash值是对象的内存地址+散列算法,算出来的一个数值
toString():
获取对象的字符串表示(将对象转换为字符串,可以看做是对象的内存地址值)
public String toString(){
//java.lang.Object @ 15db9742
return getClass().getName() + "@" + Integer.toHexString(hashCode());
//getClass().getName() - class对象的全路径(报名+类名)
//Integer.toHexString(hashCode()) - 获取对象的十六进制hash值
}
==:
基本数据类型:==比较的是值是否相同
引用数据类型:==比较的是内存地址
public class Test01 {
public static void main(String[] args) {
//基本数据类型:==比较的是值是否相同
// int a = 10;
// int b = 20;
// System.out.println(a == b);//false
//引用数据类型:==比较的是内存地址
Object obj1 = new Object();//0x001
Object obj2 = new Object();//0x002
System.out.println(obj1 == obj2);//false
System.out.println(obj1.equals(obj2));//false
}
}
getClass():
public class Test02 {
public static void main(String[] args) {
Object obj1 = new Object();//0x001
Object obj2 = new Object();//0x002
Class<? extends Object> class1 = obj1.getClass();//获取的是Object类的class对象
Class<? extends Object> class2 = obj2.getClass();//获取的是Object类的class对象
System.out.println(class1 == class2);//true
}
hashcode():
public class Test03 {
public static void main(String[] args) {
Object obj1 = new Object();//0x001
Object obj2 = new Object();//0x002
System.out.println(obj1.hashCode());//366712642
System.out.println(obj2.hashCode());//1829164700
}
toString():
public class Test04 {
public static void main(String[] args) {
Object obj1 = new Object();//0x001
Object obj2 = new Object();//0x002
System.out.println(obj1.toString());//java.lang.Object@15db9742
System.out.println(obj2.toString());//java.lang.Object@6d06d69c
}
3.Object方法的使用
getClass():在反射的知识点中使用
hashCode():在集合的知识点中使用
equals():
比较两个对象的内存地址是否相同(有==就可以)
但是他的标杆作用是比较两个对象是否相同
不同子类比较两个对象的规则不一样
所以不同子类重写equals即可
toString():
获取对象的字符串表示
他的标杆作用不同的子类有不同的属性,重写toString方便外界打印
需求:编写用户类,比较两个对象是否相同,并打印
public class User {
private String username;//账号
private String password;//密码
private String nickName;//昵称
private String name;//姓名
public User() {
}
public User(String username, String password, String nickName, String name) {
this.username = username;
this.password = password;
this.nickName = nickName;
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// user1.equals(user2):user是子类(也就是User类),equals是object类,对象的向上转型
//User类:默认父类是object类
//user1.equals(user2)
//this --> user1
//obj是传进来的参数,也就是user2
@Override
public boolean equals(Object obj) { //第一步
if(this == obj){ //比较两个内存地址是否相同
return true;
}
User use = (User) obj;//第二步 向下转型
if(this.username.equals(use.username)){ //账号是一样的true,否则false
return true; //这个equals是String类的,比较两个字符串是否相等
}
return false;
}
@Override
public String toString() {
return this.username + " -- " + this.password + " -- " + this.nickName + " -- " + this.name;
}
}
public class Test01 {
public static void main(String[] args) {
User user1 = new User("1445584980", "123123", "撕裂的忧伤", "彭于晏");//0x001
User user2 = new User("1445584980", "123123", "撕裂的忧伤", "彭于晏");//0x002
//user1,user2是否相等?从内存角度上看,new了两个对象,地址不同 从业务角度:账号一样,就一样
System.out.println(user1.equals(user2));//false
System.out.println(user1.toString());
System.out.println(user2.toString());
}
}
内存分析图:
扩展 - 注意:
1.java方法中的参数是值传递
2.如果方法中的参数是基本类型直接将实参的值传入该方法
3.如果方法中的参数是引用类型将对象的内存地址作为值传入该方法
4.深入字符串String的equals()
字符串一般不用 == 比较,因为这样比较的是内存地址,肯定是false
所以字符串比较用equals()方法
面试题:String是如何比较两个字符串是否相同的
1.比较两个字符串的地址是否相同(重写equals()方法,用 == 比较)
2.比较两个字符串的字符个数(先强转)
3.循环比较字符的Unicode码
public class MyString {
private char[] value;
public MyString(String original) {
//"abc" 转换为 ['a','b','c']
value = original.toCharArray();//将字符串转换为字符数组
}
//重写equals方法
@Override
public boolean equals(Object obj) {
if(this == obj){//比较两个内存地址是否相同
return true;
}
MyString my = (MyString) obj;//强转为MyString
char[] v1 = this.value;//当前数组
char[] v2 = my.value;//v2
//比较字符长度
if(v1.length != v2.length){
return false;
}
for (int i = 0; i < v1.length; i++) {
//长度一致,然后比较字符的Unicode码是否相同
if(v1[i] != v2[i]){
return false;
}
}
return true;
}
@Override
public String toString() {
return String.valueOf(value);//将字符数组转为字符串
}
}
public class Test01 {
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = new String("abc");
System.out.println(str1 == str2);//false 一般不用
System.out.println(str1.equals(str2));//true
System.out.println(str1);//abc
System.out.println(str2);//abc
System.out.println("-------------------------------");
MyString m1 = new MyString("abc");
MyString m2 = new MyString("abc");
System.out.println(m1 == m2);//false
System.out.println(m1.equals(m2));//true
//注意:打印对象,默认调用toString()
System.out.println(m1);//不重写toString(),就打印地址值
System.out.println(m2);//不重写toString(),就打印地址值
}
}
小结:
1.默认情况下equals方法比较的是对象的地址值
2.比较对象的地址值是没有意义的,因此一般情况下我们都会重写Object类中的equals方法
5.final
作用:
1.final修饰类,该类不能被继承
2.final修饰方法,该方法不能被子类重写
3.final修饰变量,变量变为常量,不能重新赋值
注意:
1.常量在常量池中声明,项目结束时才会被销毁
2.常量的命名规范:全部单词大写,单词之间使用下划线隔开
经验:
如果不想让该类有子类(不想该类有扩展),就是用final修饰
final和static一般一起修饰属性,该属性变成静态常量
//final修饰类,该类不能被继承
//public final class A {
public class A {
//final修饰方法,该方法不能被子类重写
//public final void method(){
public void method(){
System.out.println("父类的方法");
}
}
public class B extends A{
@Override
public void method() {
System.out.println("子类重写父类的方法");
//final修饰变量,变量变为常量,不能重新赋值
final int i = 100;
System.out.println(i);
}
}
简答题
1.final有哪些用法?
final也是很多面试喜欢问的地方,但我觉得这个问题很无聊,通常能回答下以下5点就不错了:
1.被final修饰的类不可以被继承
2.被final修饰的方法不可以被重写
3.被final修饰的变量不可以被改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变.
4.被final修饰的方法,JVM会尝试将其内联,以提高运行效率
5.被final修饰的常量,在编译阶段会存入常量池中
2.访问修饰符 public,private,protected,以及不写(默认)时的区别
定义:Java中,可以使用访问修饰符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
分类
private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
默认 : 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变 量、方法。
protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
public : 对所有类可见。使用对象:类、接口、变量、方法
3.equals与==的区别
== : ==的作用是判断两个对象的地址是不是相等,即判断两个对象是不是同一个对象。(基本数据类型比较的是值,引用数据类型比较的是内存地址)
因为 Java 只有值传递,所以,对于 == 来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址。
equals:equals用来比较的是两个对象的内容是否相等,由于所有的类都是继承自java.lang.Object类的,所以适用于所有对象,如果没有对该方法进行重写的话,调用的仍然是Object类中的方法,而Object中的equals方法返回的却是==的判断。
equals() 方法存在两种使用情况:
情况 1:类没有重写 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==” 比较这两个对象。使用的默认是 Object 类 equals() 方法。
情况 2:类重写了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true(即,认为这两个对象相等)。
注意:
String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。
总结:
所有比较是否相等时,都是用equals 并且在对常量相比较时,把常量写在前面,因为使用object的equals object可能为null 则空指针
总结
1.访问修饰符 – 一定要去做实验
2.Object的概念
equals
getClass
hashCode
toString
3.Object的使用
子类重写equals和toString
4.MyString – 重要!!!
5.final - 最终的
修饰类,类不能被继承
修饰方法,方法不能被重写
修饰变量,变为常量