面经|java基础(面向对象,异常,类,抽象类,继承类,构造方法,接口,string类,==和equals,修饰符final,static,重写和重载)

JAVA中抽象类和接口有什么区别 不同
抽象类:
1.抽象类中可以定义构造器
2.可以有抽象方法和具体方法
3.接口中的成员全都是public的
4.抽象类中可以定义成员变量
5.有抽象方法的类必须声明为抽象类,而抽象类未必要有抽象方法
6.抽象类中可以包含静态方法
7.一个类只能继承一个抽象类
接口:
1.接口中不能定义构造器
2.方法全都是抽象方法
3.抽象类中的成员可以是private,默认,protected,public
4.接口中定义的成员变量实际上是常量
5.接口中不能有静态方法
6.一个类可以实现多个接口
Java中==和equals有哪些区别 equals和==最大的区别是一个是方法一个是运算符
==:如果比较的对象时基本数据类型,则比较的是数值是否相等; 如果比较的是引用数据类型,则比较的是对象的地址值是否相等
equals(): 用来比较两个方法的内容是否相等。
注意:equals方法不能用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向二代对象的地址。
● == : 对比的是栈中的值,基本数据类型是变量值,引用数据类型是堆中内存对象的地址;
直接比较的两个对象的堆内存地址,如果相等,则说明这两个引用实际是指向同一个对象地址的
● equals:object中默认也是采用==比较,通常会重写
== 是java提供的等于比较运算符,用来比较两个变量指向的内存地址是否相同.而equals()是Object提供的一个方法.Object中equals()方法的默认实现就是返回两个对象==的比较结果.但是equals()可以被重写,所以我们在具体使用的时候需要关注equals()方法有没有被重写.
Java中重写和重载有哪些区别 方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性,重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同,参数个数不同或者二者都不同)则视为重载; 重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法生命更多的
String ,StringBuffer,StringBuilder区别及使用场景 Java平台提供了两种类型的字符串:String和StringBuilder,它们都可以存储和操作字符串,区别如下。
1.String是只读字符串,也就意味着String引用的字符串内容是不能被改变的,初学者可能会有这样的误解:

String str ="abc"; str = "bad"

如上,字符串str命名是可以改变的吖!其实不然,str仅仅是一个是一个引用对象,它指向一个字符串对象“abc”,
第二行代码的含义是让str重新指向一个新的字符串"bcd"对象,而“abc”对象并没有任何改变,只不过该对象已经成为了一个不可及对象罢了
2.StringBuffer/StringBuffer表示的字符串对象可以直接修改
3.StringBuffer是java5中引入的,它和StringBuffer的方法完全相同,区别在于它是在单线程环境下使用的,因为它的所有方法都没有被synchronized修饰,因此它的效率理论上也比StringBuffer要高。
JAVA接口 为什么要用接口
接口被用来描述一种抽象。因为JAVA不像C++一样支持多继承,所以JAVA可以通过实现接口来弥补这个局限
接口也可以用来实现解耦。
接口被用来实现抽象,而抽象类也被用来实现抽象,为什么一定要用接口呢?接口和抽象类之间又有什么区别呢?原因是抽象类内部可能包含非final的变量,接口的静态成员变量要用static final public 来修饰
\接口中的方法都是抽象的,是没有方法体的,可以使用接口类型的引用指向一个实现了该接口的对象,并且可以调用这个接口中的方法。
可以直接把接口理解为100%的抽象类,既接口中的方法必须全部是抽象方法。(JDK1.8之前可以这样理解)
和抽象类区别:
● 抽象类实例化是变量指向实现抽象方法的子类对象,接口变量必须实现所有接口方法的类对象
● 抽象类要被子类继承,接口被类实现
● 接口只能做方法申明,抽象类可以做方法实现
● 接口定义的变量只能是公共的静态的常量,抽象类中是普通变量
● 接口可以通过匿名内部类实例化
● 一个抽象类可以是public、private、protected、default,接口只有public;
● 一个抽象类中的方法可以是public、private、protected、default,接口中的方法只能是public和default
● abstract不能与final并列修饰同一个类;abstract 不能与private、static、final或native并列修饰同一个方法
● 抽象方法不能有方法体,抽象方法不能使用private修饰符,也不宜使用默认修饰符(default)接口 不可以实例化 。 通过接口实现类创建对象
JAVA构造方法
构造方法的声明: 修饰符 class_name(类名)(参数列表){ 逻辑代码 }

  1. 构造?法的?法名和类名?致(包括??写)
  2. 构造?法没有返回值类型(连void都没有)
  3. 构造?法可以重载
  4. 构造?法不可以?动调?,只能在创建对象的时,jvm?动调?
  5. 构造?法在创建对象时只能调??次
  6. 构造?法的?法名和类名?致(包括??写)
  7. 构造?法没有返回值类型(连void都没有)
  8. 构造?法可以重载
  9. 构造?法不可以?动调?,只能在创建对象的时,jvm?动调?
  10. 构造?法在创建对象时只能调??次
当?个类中,没有定义构造?法 系统会?动提供?个公开的 ?参的构造?法 当类中已经定义了构 造?法,系统不再提供?参公开构造,如果需要使??参的构造 那么必须??定义出来 ?般开发如果 定义了有参的构造 都会再定义?个?参的构造
构造方法不能被 static、final、synchronized、abstract 和 native(类似于 abstract)修饰。构造方法用于初始化一个新对象,所以用 static 修饰没有意义。构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义。
构造函数的作用是创建一个类的实例。用来创建一个对象,同时可以给属性做初始化。当程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化。
static的作用 static修饰的变量没有发生变化是因为static作用于成员变量只是用来表示保存一份副本,其不会发生变化。怎么理解这个副本呢?其实static修饰的在类加载的时候就加载完成了(初始化),而且只会加载一次也就是说初始化一次,所以不会发生变化!
static是不允许用来修饰局部变量 静态变量只能在类主体中定义,不能在方法中定义
● 静态变量:
静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中JVM只为静态变量分配一次内存空间。
● 实例变量:
每次创建对象都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。
super的作用
● 调用父类被子类重写的方法;
● 调用父类被子类重定义的字段(被隐藏的成员变量);
● 调用父类的构造方法;
如果子类没有重写父类的方法,调用父类的方法用不用super关键字结果都一样。 如果子类重写父类的方法,调用父类的方法必须用super关键字
String的底层存储是什么? 在JDK9之前,String的底层存储结构是char[],一个char需要占用两个字节的存储单位
sleep()与wait()区别? 区别1:使用限制
使用 sleep 方法可以让让当前线程休眠,时间一到当前线程继续往下执行,在任何地方都能使用,但需要捕获 InterruptedException 异常。
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
而使用 wait 方法则必须放在 synchronized 块里面,同样需要捕获 InterruptedException 异常,并且需要获取对象的锁。
synchronized (lock){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
而且 wait 还需要额外的方法 notify/ notifyAll 进行唤醒,它们同样需要放在 synchronized 块里面,且获取对象的锁。。
synchronized (lock) {
// 随机唤醒
lock.notify();
// 唤醒全部 lock.notifyAll();

}
当然也可以使用带时间的 wait(long millis) 方法,时间一到,无需其他线程唤醒,也会重新竞争获取对象的锁继续执行。
区别2:使用场景
sleep 一般用于当前线程休眠,或者轮循暂停操作,wait 则多用于多线程之间的通信。
区别3:所属类
sleep 是 Thread 类的静态本地方法,wait 则是 Object 类的本地方法。
java.lang.Thread#sleep
public static native void sleep(long millis) throws InterruptedException;
java.lang.Object#wait
public final native void wait(long timeout) throws InterruptedException;
为什么要这样设计呢?
因为 sleep 是让当前线程休眠,不涉及到对象类,也不需要获得对象的锁,所以是线程类的方法。wait 是让获得对象锁的线程实现等待,前提是要楚获得对象的锁,所以是类的方法。
区别4:释放锁
Object lock = new Object();
synchronized (lock) {
try {
lock.wait(3000L);
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
如上代码所示,wait 可以释放当前线程对 lock 对象锁的持有,而 sleep 则不会。
【面经|java基础(面向对象,异常,类,抽象类,继承类,构造方法,接口,string类,==和equals,修饰符final,static,重写和重载)】区别5:线程切换
sleep 会让出 CPU 执行时间且强制上下文切换,而 wait 则不一定,wait 后可能还是有机会重新竞争到锁继续执行的。

    推荐阅读