一、Object类
Object:超类、基类;它是所有类的父类。
一个类没有明确继承其他类,则默认继承Object类。
1、equals()方法
equals()功能:比较两个对象的内存地址是否相同
//equals底层
public boolean equals(Object obj) {
return (this == obj);
}
在String类中,“==”比较对象的内存地址是否相同,equals比较内容是否相同。
对于基本数据类型,"=="比较内容是否相同。
2、toString()方法
把对象转为字符串,打印对象时被调用。
//toString()底层
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
例:
public static void main(String[] args) {
Object o1 = new Object();
Object o2 = new Object();
System.out.println(o1.equals(o2));
//输出对象,默认调用toString()
System.out.println(o1);//java.lang.Object@1cd0888
System.out.println(o1.toString());//java.lang.Object@1cd0888
//toString显示代码实现
//获取到的是在方法区中Object.class对象
Class objClass = o1.getClass();
//获取该类的全路径:java.lang.Object
String name = objClass.getName();
System.out.println(name);//java.lang.Object
//获取该对象的hash值
int hashCode = o1.hashCode();
//再把十进制的hash值转换为十六进制
String hexString = Integer.toHexString(hashCode);
System.out.println(hexString);//1cd0888
}
3、getClass()
获取当前类的字节码文件的对象。
见上述代码。
4、hashCode()
获取对象的hash值。见上述代码。
二、重写Object类中的equals方法
String类的equals方法是重写的,与Object类功能不一样。
“==”比较对象的内存地址是否相同,equals比较内容是否相同。
为什么要重写equals和hashCode?
场景:酒店用身份证查询入住 在程序中:登记的前台好比哈希算法,名字是对比好比 equals
方法,身份证号的对比好比 hashcode 方法只有equals 和 hashcode 都满足的时候才能确保是同一个对象。当我们重写一个类的 equals 方法时就应当连同重写 hashcode 方法,并且两个方法应满足: 1:一致性,即:当两个对象
equals 比较为 true,那么 hashcode 值应当相等,反之亦然,因为当两个对象hashcode 值相等,但是 equals
比较为 false,那么在 HashMap 中会产生链表,影响查询性能。 2:成对重写,即重写 equals 就应当重写 hashcode。
String str1 = new String("123");
String str2 = new String("123");
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2)); //true
System.out.println(str1);//123
仿照String类型的equals方法和toString方法重写Object类的equals和toString,将该类命名为MyString:
public class MyString {
private String value;
public MyString(String value) {
this.value = value;
}
@Override
public boolean equals(Object obj) {
MyString m2 = (MyString) obj;
//把this(m1)和m2对象里存的value值-“123”取出来,并转换为字节数组
char[] charArray1 = this.value.toCharArray();
char[] charArray2 = m2.value.toCharArray();
if(charArray1.length != charArray2.length){
return false;
}
for (int i = 0; i < charArray1.length; i++) {
if(charArray1[i] != charArray2[i]){
return false;
}
}
return true;
}
@Override
public String toString() {
return value;
}
}
MyString m1 = new MyString("123");
MyString m2 = new MyString("123");
System.out.println(m1 == m2);//false
System.out.println(m1.equals(m2));//true
System.out.println(m1);//123
三、final关键词
final:最终的
* 修饰类:类不能被继承
* 修饰方法:方法不能被重写
* 修饰变量:变量不能被重新赋值----常量
* ps:
* 1.常量存储在常量池里,项目结束时才会被销毁
* 2.常量的命名规范:单词全部大写,单词与单词之间用下划线隔开
*
* 面试题:String类为什么是final类
* 1.遵循了String类的不变性
* 2.用final修饰的类里的方法自动成为JVM里的内联函数,调用效率更高
//此类不能被继承
//public final class Father {
public class Father {
// 子类不能被重写
// public final void eat(){
public void eat(){
System.out.println("哈哈");
//常量
final String CLASS_ID = "1903";
System.out.println(CLASS_ID);
}
}
四、抽象类和抽象方法
抽象类定义规则:
(1)抽象类和抽象方法都必须用abstract关键字修饰。
(2)抽象类不能被直接实例化,也就是不能直接用new关键字去产生对象。
(3)抽象方法只需声明,而不需实现。
(4)含有抽象方法的类必须被声明为抽象类,抽象类的子类必须重写所有的抽象方法后才能被实例化,否则这个子类还是个抽象类。
//抽象类
public abstract class Person {
//抽象方法:交给非抽象的子类去重写
public abstract void eat();
}
- 1.抽象类里可以有属性吗?可以
- 2.抽象类里可以有非抽象方法吗?可以
- 3.抽象类可以创建对象吗?不可以,创建的是匿名子类的对象
- 4.抽象类是否有构造方法?有
- 5.抽象类的构造方法有什么用?初始化数据
- 6.抽象类里可以没有抽象方法吗?可以,没意义
- 7.如果父类是抽象类,则子类必须重写父类的抽象方法?不一定,子类如果是抽象类,就可以不去重写
Person是一个抽象类,创建的不是Person的对象
匿名内部类:创建了一个没有名的类,继承了Person,重写了eat方法
Person person = new Person() {
@Override
public void eat() {
}
};
需求:老师骑着自行车上班
需求优化:自行车 --> 小汽车 --> 飞机
主方法
public static void main(String[] args) {
//多态:子类对象指向父类引用
Teacher t = new Teacher();
Transport tool = new Car();
t.start(tool);
t.stop(tool);
}
老师类
public class Teacher {
public void start(Transport tool) {
tool.start();
}
public void stop(Transport tool) {
tool.stop();
}
}
父类-交通工具类-抽象类
public abstract class Transport {
abstract void start();
abstract void stop();
}
子类-汽车
public class Car extends Transport{
@Override
void start() {
System.out.println("小汽车启动了");
}
@Override
void stop() {
System.out.println("小汽车停止了");
}
}
子类-自行车
public class Bike extends Transport{
@Override
void start() {
System.out.println("自行车启动了");
}
@Override
void stop() {
System.out.println("自行车停止了");
}
}
自创同类例子:
需求:一个人选择了一位英雄,并了解其技能。
主方法
public static void main(String[] args) {
Person p = new Person("小羊同学");
Hero hero= new Kass("kass");
System.out.println(p.getName()+"选择的英雄是:"+hero.getName()+",他的技能是:");
hero.Skills();
}
}
父类-英雄类(名字,抽象方法)
public abstract class Hero {
private String name;
public Hero() {}
public Hero(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public abstract void Skills();
}
子类卡萨丁(姓名,方法)
public class Kass extends Hero{
public Kass() {}
public Kass(String name) {
super.setName(name);
}
@Override
public void Skills() {
System.out.println("Q能触发魔法护盾!");
System.out.println("主E吊打Yasuo");
}
}
子类奥拉夫(姓名,方法)
public class Aolafu extends Hero{
public Aolafu() {}
public Aolafu(String name) {
super.setName(name);
}
@Override
public void Skills() {
System.out.println("斧子可刷新");
System.out.println("铁头娃,B键已扣");
}
}
人类
public class Person {
String name;
public Person() {}
public Person(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void pickHero(Hero hero) {
hero.Skills();
}
}
输出结果
五、接口
接口:特殊的抽象类
与抽象类的区别:
(1)接口里的数据成员必须初始化,且数据成员均为常量;
(2)接口里的方法必须全部声明为abstract,也就是说,接口不能像抽象类一样保有一般的方法,必须全部是“抽象方法”。
利用接口打造新的类的过程,称之为接口的实现(implementation)。
有的人可能会觉得这样做与抽象类并没有什么不同,在这里需要再次提醒的是:接口是Java实现多继承的一种机制,一个类只能继承一个父类,但如果需要一个类继承多个抽象方法的话,就无法实现,因此出现了接口的概念。一个类只可以继承一个父类,但却可以实现多个接口。
一个接口可以同时继承多个接口,也就是同时继承了多个接口的抽象方法与常量。
ps:
1.接口更多的是描述一个标准
2.接口里只能有常量或者抽象方法
应用场景:抽象类里只有常量或抽像方法时用接口代替
类 与 类:单继承 A extends B
类 与 接口:多实现 A implements B,C
接口与接口:多继承 A extends B,C,D
public abstract interface IPerson{
public abstract void eat();
}
简写,接口默认abstract,接口名以I开头。
public interface IPerson{
public void eat();
}
//实现类 实现 多接口
public class Chinese implements IPerson,I1,I2
//一个类继承另一个类并实现多个接口
public class Japanese extends Object implements IPerson,I1,I2
OCP-开闭原则:
* O - open :对创建欢迎的
* C - close:对修改关闭的
* p - princeple:原则
需求:选择电脑上的硬件,了解其功能
public static void main(String[] args) {
Computer computer = new Computer();
IUSB usb = new Disk();
computer.connection(usb);
}
电脑类
public class Computer {
public void connection(IUSB usb) {
usb.use();
}
}
接口类
public abstract interface IUSB {
public abstract void use();
}
硬盘类
public class Disk implements IUSB{
@Override
public void use() {
System.out.println("我是硬盘");
}
}
鼠标类
public class Mouse implements IUSB{
@Override
public void use() {
System.out.println("我是鼠标");
}
}
六、对象转型
向上转型:
子类类型转父类类型
可以获取父类非私有化的属性和方法
可以获取子类重写父类后的方法
**缺点:**不能获取到子类的属性及方法
父类
public class Father {
String fatherAtrr = "父类属性";
public void fatherMethod(){
System.out.println("父类方法");
}
public void fatherMethod2(){
System.out.println("父类方法");
}
}
子类
public class Son extends Father{
String sonAtrr = "子类属性";
public void sonMethod(){
System.out.println("子类方法");
}
public void fatherMethod2(){
System.out.println("子类重写父类的方法");
}
}
public static void main(String[] args){
Father f = new Son();
System.out.println(f.fatherAtrr);
f.fatherMethod();
f.fatherMethod2();
}
向下转型(不安全):
父类类型转子类类型
public class Dog extends Animal{
String attr = "狗";
}
public class Cat extends Animal{
String attr = "猫";
}
public static void main(String[] args){
//下转型一定要用instancdof判断
Animal an = new Dog();
if(an instanceof Cat){//判断an这个引用对应的对象是否是Cat的类型
Cat cat = (Cat) an;//下转型
System.out.println(cat.attr);
}else if(an instanceof Dog){
Dog dog = (Dog) an;
System.out.println(dog.attr);//下转型
}
}
输出:狗