1.java中String两种实例化对象
在Java中String并不是一个数据类型,而是引用数据类型
创建方式的区别
作为特殊类,其创建方式有两种
String strA= "mldn"; String str = "mldn"; String strB = new String("mldn");
下面介绍其区别:
编辑
strA在堆上创建mldn空间,而strB的实例化中有new 即新创建一个空间内容也是mldn,而strc内容是mldn与strA是一致的,所以不会再分配新的空间,而是直接将strC的栈地址直接指向strA的堆地址
*面试题:new String("a") + new String("b") 会创建几个对象?
对象1:new StringBuilder()
对象2:new String("a")
对象3:常量池中的"a"
对象4:new String("b")
对象5:常量池中的"b"
深入剖析:StringBuilder中的toString():
对象6:new String("ab")
强调一下,toString()的调用,在字符串常量池中,没有生成"ab"
面试题 String str="i"与 String str=new String(“i”)一样吗?
String str="i"会将起分配到常量池中,常量池中没有重复的元素,如果常量池中存中i,就将i的地址赋给变量,如果没有就创建一个再赋给变量。
String str=new String(“i”)会将对象分配到堆中,即使内存一样,还是会重新创建一个新的对象。
2.Annotation注解类
1.@Override 准确性覆写类
覆写发生在子类中有一个和父类相同方法名、相同参数列表和相同返回类型的方法时。在一般情况下,通过子类对象调用该方法时,会直接调用子类中的方法。这是因为子类方法覆盖了父类方法,所以会优先调用子类的方法实现。
然而,如果在某些情况下出现错误,可能会导致错误地调用父类的方法,例如:
- 子类方法的签名与父类方法不一致:如果子类中定义的方法签名与父类的方法签名不完全匹配,例如参数列表不同,那么不会发生准确性覆写,而是子类创建了一个新的方法,和父类的方法没有关联。此时,通过子类对象调用方法时,会调用到父类的方法。
- 在子类中使用了
super
关键字:子类中可以使用super
关键字调用父类的方法,即使发生了准确性覆写。在这种情况下,通过super
关键字调用的是父类的方法,而不是子类的方法。
所以通过@Override就可以避免出现上述问题从而正常调用子类
package Example82; class father{ public void function(){ System.out.println("执行父亲函数的"); } } class son extends father{ @Override public void function(){ System.out.println("利用@Override准确性覆写执行子函数"); } } public class javaDemo { public static void main(String[] args) { son s = new son(); s.function(); } }
编辑
2.@Deprecated过期声明注解
当一个类可能已经不符合生产的需求后,但是如果随便删除这个类可能会导致整个程序结构的不稳定从而出错,所以java中就有@Deprecated过期声明注解,在用该注解后某个类或者某个方法将不再建议使用。如果调用则会在方法上加上
删除线
编辑
*面试题: 在 Java 中,什么时候用重载,什么时候用重写?
(1)重载是多态的集中体现,在类中,要以统一的方式处理不同类型数据的时候,可以用重载。
(2)重写的使用是建立在继承关系上的,子类在继承父类的基础上,增加新的功能,可以用重写。
(3)简单总结:
重载是多样性,重写是增强剂;
目的是提高程序的多样性和健壮性,以适配不同场景使用时,使用重载进行扩展;
目的是在不修改原方法及源代码的基础上对方法进行扩展或增强时,使用重写;
3.多态
1.向上转型
向上转型 即大范围转到小范围 比如 动物和狗,动物就是父类,狗是子类,这种往下细分的操作就叫向上转型
父类 name = new 子类();
为什么要出现向上转型
- 统一接口:通过向上转型,可以将不同子类的对象都当作父类类型来处理。这样可以使用统一的接口对这些对象进行操作,简化了代码的编写和维护。如果有多个子类,使用向上转型可以避免针对每个子类都编写相似的代码段,提高了代码的重用性。
- 扩展性:通过向上转型,可以更加方便地扩展代码,增加新的子类,而无需修改已有的代码。这是因为向上转型使得代码与具体子类解耦,如果需要增加一个新的子类,只需要修改创建对象的部分,而不需要修改其他已经存在的代码逻辑。
- 可替换性:通过向上转型,可以实现对子类对象的替换。即使使用父类引用变量来引用子类对象,仍然可以调用子类中重写的方法,实现对父类引用的灵活使用。这使得程序在后续的维护和扩展过程中更加方便,可以根据需要轻松地切换不同的子类实现。
package Example84; class Animal { public void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override public void sound() { System.out.println("Dog barks"); } public void playFetch() { System.out.println("Dog plays fetch"); } } class Cat extends Animal { @Override public void sound() { System.out.println("Cat barks"); } public void playFetch() { System.out.println("Cat plays fetch"); } } public class javaDemo { public static void main(String[] args) { Animal animal = new Dog(); // 向上转型 animal.sound(); animal = new Cat(); animal.sound(); } }
编辑
通过向上转型,我们可以实例化一个 Animal 对象,并且通过该对象引用子类对象,从而灵活地切换它们之间的关系。然而,向上转型有一个重要限制,即我们只能调用父类中定义的方法,或者子类中覆盖了的方法。这意味着,一些子类特有的功能将无法直接通过父类引用调用。例如,在上述代码中,我们可以使用 animal.sound()
调用 Animal 类中的 sound 方法,但无法使用 animal.playFetch()
调用 Dog 或 Cat 类特有的 playFetch 方法。
为此就有了向下转型
2.向下转型
条件:必须要在向上转型的基础上才能进行向下转型,否则父类与子类无关联的情况下无法进行联系
案例代码:
package Example84; class Animal { public void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override public void sound() { System.out.println("Dog barks"); } public void playFetch() { System.out.println("Dog plays fetch"); } } public class javaDemo { public static void main(String[] args) { Animal animal = new Dog(); // 向上转型 ((Dog) animal).playFetch();//强制向下转型 Dog dog = (Dog) animal;//第二种强制向下转型 dog.playFetch(); } }
编辑
3.instanceof关键字(判断是否能向下转型)
当使用了向上转型后,将子类的实例赋值给父类的引用变量时,就会丧失对子类特有方法的直接访问能力。此时,如果想要调用子类的方法,就需要进行安全转型,即使用
instanceof
检查对象是否为某个特定类型,并在确认类型后进行强制转型。
在这种情况下,如果我们直接调用子类的方法而没有进行安全转型,会导致编译错误,因为编译器只知道引用变量的静态类型,而无法确定运行时实际对象的类型。这样的错误可能会导致程序在运行时抛出 ClassCastException 异常,因为尝试将父类引用转换为子类类型是非法的。
用法: 实例化对象名称 instanceof 类 返回boolean类型的值
package Example84; class Animal { public void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override public void sound() { System.out.println("Dog barks"); } } public class javaDemo { public static void main(String[] args) { Animal animal = new Animal(); System.out.println(animal instanceof Animal); System.out.println(animal instanceof Dog); Animal animal1 = new Dog(); System.out.println(animal1 instanceof Animal); System.out.println(animal1 instanceof Dog); } }
编辑
具体应用
编辑
4.Object类
1.概述
1.在Java中,
Object
类是所有类的根类,也可以说是所有类的父类。它定义了一些通用的方法,如equals()
、hashCode()
和toString()
等。当我们定义一个类时,如果没有显式指定它的父类,那么默认情况下该类会直接继承自Object
类。因此,你可以将其视为所有类的隐式父类。然而,并不是所有类型的数据都可以被向上转型为
Object
类型。在Java中,基本类型(如int
、boolean
、char
等)是不能直接向上转型为Object
类型的。相反,只有引用类型(如类、接口等)可以被向上转型为Object
类型。在Java中,当我们将一个引用类型的对象向上转型为
Object
类型时,它实际上已经是Object
类型的对象了,但是我们只能通过Object
类型的引用变量访问Object
类中定义的方法,无法直接调用原始类型的方法。如果我们想要调用原始类型的方法,就需要进行向下转型(即安全强制类型转换)。因此,尽管
Object
类可以作为所有类的父类,但并不意味着它可以接受所有类型的数据。只有引用类型可以被向上转型为Object
类型,而基本类型不能。同时,为了调用子类特有的方法,还需要进行向下转型。
2.Object的toString方法
package Example84; class Animal extends Object{ public void sound() { System.out.println("Animal makes sound"); } } class Dog extends Animal { @Override public void sound() { System.out.println("Dog barks"); } public void fectch(){ System.out.println("Dog fectch"); } @Override public String toString(){ return "直接打印一个类,其实是调用了Object类中的toString函数"; } } public class javaDemo { public static void main(String[] args) { Animal animal = new Dog(); System.out.println(animal); } }
编辑
面试题:hashcode是什么?有什么作用?
Java中Object有一个方法:
public native int hashcode();
(1)hashcode()方法的作用
1.hashcode()方法主要配合基于散列的集合(相关知识在java的类集中进行学习)一起使用,比如HashSet、HashMap、HashTable。
当集合需要添加新的对象时,先调用这个对象的hashcode()方法,得到对应的hashcode值,实际上hashmap中会有一个table保存已经存进去的对象的hashcode值,如果table中没有改hashcode值,则直接存入,如果有,就调用equals方法与新元素进行比较,相同就不存了,不同就存入。
(2)equals和hashcode的关系
如果equals为true,hashcode一定相等;
如果equals为false,hashcode不一定不相等;
如果hashcode值相等,equals不一定相等;
如果hashcode值不等,equals一定不等;
(3)重写equals方法时,一定要重写hashcode方法
Object还有非常多的方法将在以后章节展现