面向对象基础
面向对象和面向过程的区别?
区别主要在 解决问题的方式不同
面向过程吧解决问题的过程拆分为一个个方法,通过一个个方法解决问题
面向对象是先抽象出对象,然后用对象执行方法的方式解决问题
面向对象一般易维护 易复用 易扩展
面向过程性能比面向对象高?
面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。
对象实体和对象引用有何不同?
对象是new出来的
对象实例 是在堆内存中的
对象引用 是指向对象实例的
对象的相等和引用相等的区别
-
对象的相等一般比较的是内存中存放的内容是否相等。
-
引用相等一般比较的是他们指向的内存地址是否相等。
如果一个类没有声明构造方法的话,该程序能正确的执行吗?
构造方法是一种特殊的方法:主要作用是为了完成对象的初始化工作
没有声明构造方法也可以执行(因为会有默认不带参数的构造方法)
无论怎样也要把无参的构造方法写出来
构造方法的特点?
没有返回值
生成类的对象自动执行,无需调用
不能override 可以 overload
面向对象三大特征
封装
把对象的属性隐藏在对象内部,不允许外部对象直接访问对象的内部信息,但是可以提供一些外界可以访问的方法
继承
继承就是在已经存在的类的基础上,新定义的类可以使用新的数据和功能
也可以使用父类的功能
易维护 易复用 易扩展
关于继承如下 3 点请记住:
-
子类拥有父类对象所有的属性和方法(包括私有属性和私有方法),但是父类中的私有属性和方法子类是无法访问,只是拥有。
-
子类可以拥有自己属性和方法,即子类可以对父类进行扩展。
-
子类可以用自己的方式实现父类的方法。
多态
顾名思义 多种状态,具体表现为父类的引用指向子类的实例
多态的特点:
-
对象类型和引用类型之间具有继承(类)/实现(接口)的关系;
-
引用类型变量发出的方法调用的到底是哪个类中的方法,必须在程序运行期间才能确定;
-
多态不能调用“只在子类存在但在父类不存在”的方法;
-
如果子类重写了父类的方法,真正执行的是子类覆盖的方法,如果子类没有覆盖父类的方法,执行的是父类的方法。
接口和抽象类有什么共同点和区别?🌶
共同点1️⃣都不能被实例化
2️⃣都包含抽象方法
3️⃣都可以有默认实现的方法(default)
区别🤠===================================================
接口主要用于对类的行为约束 实现了某个对应的行为
抽象类主要用于代码复用,强调的是所属关系
一个类只能继承一个类,但是可以实现多个接口
接口中的成员变量只能是 public static final
类型的,不能被修改且必须有初始值,而抽象类的成员变量默认 default,可在子类中被重新定义,也可被重新赋值。
深拷贝和浅拷贝区别了解吗?什么是引用拷贝?
浅拷贝:浅拷贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内部的属性是引用类型的话,浅拷贝会直接复制内部对象的引用地址,也就是说拷贝对象和原对象共用同一个内部对象。
深拷贝 :深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
实现Cloneable接口 调用clone()方法
引用拷贝:两个不同引用指向同一个对象
Object
object常见的方法有哪些?
/**
* native 方法,用于返回当前运行时对象的 Class 对象,使用了 final 关键字修饰,故不允许子类重写。
*/
public final native Class<?> getClass()
/**
* native 方法,用于返回对象的哈希码,主要使用在哈希表中,比如 JDK 中的HashMap。
*/
public native int hashCode()
/**
* 用于比较 2 个对象的内存地址是否相等,String 类对该方法进行了重写以用于比较字符串的值是否相等。
*/
public boolean equals(Object obj)
/**
* naitive 方法,用于创建并返回当前对象的一份拷贝。
*/
protected native Object clone() throws CloneNotSupportedException
/**
* 返回类的名字实例的哈希码的 16 进制的字符串。建议 Object 所有的子类都重写这个方法。
*/
public String toString()
/**
* native 方法,并且不能重写。唤醒一个在此对象监视器上等待的线程(监视器相当于就是锁的概念)。如果有多个线程在等待只会任意唤醒一个。
*/
public final native void notify()
/**
* native 方法,并且不能重写。跟 notify 一样,唯一的区别就是会唤醒在此对象监视器上等待的所有线程,而不是一个线程。
*/
public final native void notifyAll()
/**
* native方法,并且不能重写。暂停线程的执行。注意:sleep 方法没有释放锁,而 wait 方法释放了锁 ,timeout 是等待时间。
*/
public final native void wait(long timeout) throws InterruptedException
/**
* 多了 nanos 参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上 nanos 毫秒。。
*/
public final void wait(long timeout, int nanos) throws InterruptedException
/**
* 跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念
*/
public final void wait() throws InterruptedException
/**
* 实例被垃圾回收器回收的时候触发的操作
*/
protected void finalize() throws Throwable { }
🙉== 和 equals() 的区别
== 对于基本类型和引用类型的作用效果是不同的
对于基本数据类型来说 比较的是值
对于引用类型来说 比较的是内存地址
equals():只能判断引用类型
public boolean equals(Object obj) {
return (this == obj);
}
没有重写的话 还是通过"=="比较的是内存地址
重写的话比较的是对象属性
String类的equals()方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
hashCode()有什么用?
获取哈希码 也称散列码
确定该对象在哈希表中的索引位置
为什么要有hashCode()?
如果两个对象的hashCode
值相等,那这两个对象不一定相等(哈希碰撞)。
如果两个对象的hashCode
值相等并且equals()
方法也返回 true
,我们才认为这两个对象相等。
如果两个对象的hashCode
值不相等,我们就可以直接认为这两个对象不相等
提供了准确率 也 提供了效率
为什么重写 equals() 时必须重写 hashCode() 方法?
因为两个相等的对象的 hashCode
值必须是相等。也就是说如果 equals
方法判断两个对象是相等的,那这两个对象的 hashCode
值也要相等。
如果重写 equals()
时没有重写 hashCode()
方法的话就可能会导致 equals
方法判断是相等的两个对象,hashCode
值却不相等。
🥀String
String StringBuffer StringBuilder区别
可变性: String不可变 StringBuffer和StringBuilder是可变的
线程安全性:String安全 StringBuffer(synchronized)安全 StringBuilder不安全
性能:StringBuilder性能会比Buffer高(10%-15%)
总结: 操作 少量数据 用String
单线程:StringBuilder
多线程:StringBuffer
来来来瞧一瞧看一看🗳String为什么是不可变的?
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[];
//...
}
String类时由final关键字修饰的
且String没有提供修改字符串的方法 且不能被继承进而避免了修改
public final class String implements java.io.Serializable,Comparable<String>, CharSequence {
// @Stable 注解表示变量最多被修改一次,称为“稳定的”。
@Stable
private final byte[] value;
}
abstract class AbstractStringBuilder implements Appendable, CharSequence {
byte[] value;
}
String"+"拼接
本质是创建StringBuilder 调用append()的方法
缺陷就是::编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象。
这意味着每循环一次就会创建一个 StringBuilder
对象。
字符串的常量池作用了解过吗?🐻
字符串常量池 是 JVM 为了 提升性能 和 减少内存消耗 针对 字符串(String 类)专门开辟的一块区域,主要目的是为了避免字符串的重复创建。
String s1 = new String("abc");这句话创建了几个字符串对象?
1个或2个
常量池 和 堆
String 类型的变量和常量做“+”运算时发生了什么?
String str1 = "str";
String str2 = "ing";
String str3 = "str" + "ing";
String str4 = str1 + str2;
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false
对于编译期可以确定值的字符串,也就是常量字符串 ,jvm 会将其存入字符串常量池。并且,字符串常量拼接得到的字符串常量在编译阶段就已经被存放字符串常量池,这个得益于编译器的优化。
引用的值在程序编译期是无法确定的,编译器无法对其进行优化。
不过final修饰后,可当做常量处理
final String str1 = "str";
final String str2 = "ing";
// 下面两个表达式其实是等价的
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 常量池中的对象
System.out.println(c == d);// true