牛客网JAVA开发面经总结—JavaSE部分基础(一)—Java基础(2)

Java异常处理

1.Java语言如何进行异常处理,几个关键词有什么含义,try块中可以抛出异常吗?

1)Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类(分装成类),并提供了良好的接口。在 Java 中,每个异常都是一个对象,它是 Throwable 类或其它子类的实例。
2)当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。
3)Java 的异常处理是通过 5 个关键词来实现的:try、catch、throw、throws和 finally。
一般情况下是用 try 来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理。
用 try 来指定一块预防所有”异常”的程序。
紧跟在 try 程序后面,应包含一个 catch 子句来指定你想要捕捉的”异常”的类型。throw 语句用来明确地抛出一个”异常”。throws 用来标明一个成员函数可能抛出的各种”异常”。
Finally 为确保一段代码不管发生什么”异常”都被执行的一段代码。
4)可以在一个成员函数调用的外面写一个 try 语句,在这个成员函数内部写另一个 try语句保护其他代码。每当遇到一个 try 语句,”异常“的框架就放到堆栈上面,直到所有的 try语句都完成。如果下一级的 try 语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的 try 语句。

1.面向对象

1.0 面向对象的特征有哪些方面

1)抽象:忽略主体中与【当前目标】无关的部分,注重与【当前目标】有挂的部分,只选择一部分了解,忽略细节部分。主要包括:过程抽象和数据抽象;
2)封装:把数据和过程包裹起来封装成一个对象,对数据的访问只能通过已经定义的方法,这些对象通过受保护的接口访问其他对象;
面向对象计算始于这个基本概念,
3)继承:是一种联结类的层次模型,允许、鼓励类的重用,提供了一种明确表述共性的方法;
对象的一个新类可以从现有的类中派生得到,这个过程称为继承,新类继承原始类的特性;
新类称为原始类的派生类,原始类称为新类的基类;
类可以从它的基类那里继承方法和实例变量,并且可以修改或新增方法以更适合特殊的需要;
4)多态:指允许不同【类的对象】对统一消息作出响应。
多态包含:参数化多态性和包含多态性;
多态性语言具有灵活、抽象、行为共享、代码共享的优势,很好的解决了应用程序函数重名的问题;

1.1 类与对象的区别

1)类是对一类事物的描述,是抽象的;类是一组函数、变量的集合体,即一组具有相同属性的对象集合体。
2)对象是一个实实在在的个体,是类的一个具体实例。
对象是函数、变量的集合体。
比如:“人”是一个大类,而“我”是“人”的一个具体的实例;

1.2 wait()方法底层原理(notify()、notifyAll())

wait()方法会将当前线程放入wait set中等待被唤醒。
1)使用wait()时,需要先对调用对象加锁;
2)ObjectSynchronizer::wait方法通过object对象找到ObjectMonitor对象,调用它的ObjectMonitor::wait方法;
3)将当前线程封装成ObjectWaiter对象节点node,线程状态由Running变为waiting;
4)通过临界资源对象的监视器ObjectMonitor::addwaiter方法将node添加到waitset队列末尾,最终底层的thread_ParkEvent->park方法会挂起线程;
5)notify()方法就是随机将等待队列的一个等待线程移到同步队列中;
notifyAll()就是将等待队列种所有的线程全部移到同步队列;
notify()方法调用后等待线程不会马上从wait返回,而是移动到同步队列,线程状态由 Waiting 变为 Blocked,需要调用notify的线程释放,即线程执行完毕,ObjectMonitor执行了exit方法释放锁之后才有机会从wait返回;
6)临界资源对象的监视器ObjectMonitor::exit方法可以释放当前的ObjectMonitor对象,释放锁,这样其他竞争线程就可以获取该ObjectMonitor对象。
在这里插入图片描述
最简练的描述:WaitThread(竞争失败的线程)获得了对象的锁,调用对象的 wait 方法,放弃了锁,进入的等待队列;然后 NotifyThread (竞争成功的线程)拿到了对象的锁,然后调用对象的 notify 方法,将 WatiThread 移动到同步队列中,最后,NotifyThread 执行完毕,释放锁, WaitThread 再次获得锁并从 wait 方法返回继续执行。

1.3 请列举你所知道的Object类的方法

1)Object()默认构造方法;
2)clone()创建并返回此对象的一个副本;
3)equals()指示某个其他对象是否与此对象相等,默认是指内存地址是否一样;
4)toString()返回该对象的字符串表示;
5)hashcode()返回该对象的hash码值;
6)getClass()返回一个对象的运行时类;
7)notify()唤醒某个在此对象的监视器上等待的线程;(这个对象是被需要的资源)
8)notifyAll()唤醒所有在此对象的监视器上等待的线程;(这个对象是被需要的资源)
9)wait()导致当前的线程等待,直到其他线程调用此对象的notify()方法或调用notifyAll()方法。
10)wait(long timeout)导致当前的线程等待,直到其他线程调用此对象的notify()方法或调用notifyAll()方法,或者超过指定的时间timeout。
11)wait(long timeout, int nanos)导致当前的线程等待,直到其他线程调用此对象的notify()方法或调用notifyAll()方法,或者超过指定的时间timeout,或者其他某个线程中断当前线程。
12)finalize()当垃圾回收机制确定不再存在该对象更多的引用时,由对象的垃圾回收器调用该方法。

1.4 重载和重写的区别

I.重载(Overloading)(编译时的多态性)
1)重载是类中多态性的一种表现,让类以统一的方式处理不同类型数据的一种手段。
2)Java的重载就是在类中创建多个同名函数,但它们具有不同的参数列表(参数个数/类型不同)和返回值。调用方法时,通过传递给它们的参数个数和类型来判断具体使用哪个方法(但是当参数列表相同,返回类型不同时,无法判断具体使用哪个方法),这就是多态性;
II.重写(Overriding)(运行时的多态性)
1)方法重写又称为方法覆盖,是父类和子类间的一种多态性;
2)Java中,子类可以继承父类中的方法,无需重新编写相同的方法;但如果子类中定义的某个方法与父类的某个方法有相同的【方法名、参数列表和返回值】,我们说父类的该方法被子类重写(覆盖);子类重写父类的方法,要求重写后的方法比父类的方法更好访问,不能比父类的方法声明更多异常(里氏替换原则)
3)在子类的方法中如需访问父类中的原有方法可以使用super关键字,其引用了当前类的父类。
4)子类方法的访问修饰权限不能少于父类该方法的访问修饰权限。

1.5 类加载器、双亲委派机制

I.类加载器
1)什么是类加载器
答:类加载器是jre的一部分,负责将类加载到Java 虚拟机
2)类加载分类
①启动类加载器 bootstrap classloader :加载 jre/lib/rt.jar
②扩展类加载器 extension classloader :加载 jre/lib/ext/*.jar
③应用程序类加载器 application classloader:加载classpath上指定的类库
在这里插入图片描述
II.双亲委派机制
1)概念
双亲委派机制是指当一个类加载器收到一个类加载请求时,该类加载器首先会把请求委派给父类加载器。
每个类加载器都是如此,只有在父类加载器在自己的搜索范围内找不到指定类时,子类加载器才会尝试自己去加载。
2)工作流程
a.当Application ClassLoader 收到一个类加载请求时,不会自己去尝试加载这个类,而是将这个请求委派给父类扩展加载器Extension ClassLoader去完成。
b.当Extension ClassLoader收到一个类加载请求时,也不会自己去尝试加载这个类,而是将请求委派给父类加载器Bootstrap ClassLoader去完成。
c.如果Bootstrap ClassLoader加载失败(在<JAVA_HOME>\lib中未找到所需类),就会让Extension ClassLoader尝试加载。
d.如果Extension ClassLoader也加载失败,就会使用Application ClassLoader加载。
e.如果Application ClassLoader也加载失败,就会使用自定义加载器去尝试加载。
f.如果均加载失败,就会抛出ClassNotFoundException异常。
3)好处
①Java类随着它的类加载器一起具备了一种带有优先级的层次关系;例如java.lang.Object,它存在与rt.jar启动类加载器中,无论哪一个类加载器要加载它,最终都是最顶端的Bootstrap ClassLoader类加载器进行加载,因此Object类在程序的各个【类加载器环境】中都是同一个类;
②如果不使用双亲委派机制,由各个类自行加载。那比如用户编写了一个java.lang.Object类的【同名类】放在ClassPath中,那么由应用程序类加载器加载的是这个同名类而不是最顶端启动类加载器加载的原Object类,顶端的启动类加载器加载是原Object类,导致系统出现多个不同的类,程序会混乱。
③同时为了防止混乱,如果在rt.jar中编写重名Java类,那么这个自己编写的重名类可以正常编译,但是永远不会被加载运行;

1.6 通过反射创建对象(待总结)

1)通过【类对象】调用newInstance()方法
如:类名.class.newInstance();
2)通过【类对象】的getConstructor()或getDeclaredConstructor()方法获得构造器对象,然后调用其newInstance()方法创建对象
如:类名.class.getConstructor(类名.class).newInstance(构造器所需参数列表);

1.6.2 通过反射获取和设置对象私有字段的值

可以通过类对象的 getDeclaredField()方法获取到字段(Field)对象,然后再通过字段对象的setAccessible(true)将其设置为可以访问,接下来就可以通过 get/set 方法来获取/设置字段的值了。下面的代码实现了一个反射的工具类,其中的两个静态方法分别用于获取和设置私有字段的值 ,字段可以是基本类型也可 以是对象类型且支持多级对象操作,例 如
ReflectionUtil.get(dog, “owner.car.engine.id”);可以获得 dog 对象的主人的汽车的引擎的ID 号。

1.6.3 通过反射获取和设置对象的方法
import java.lang.reflect.Method;
class MethodInvokeTest {
// 
public static void main(String[] args) throws Exception {
	String str = "hello";
	Method m = str.getClass().getMethod("toUpperCase");
	System.out.println(m.invoke(str));	//  HELLO
	}
}
1.7 java支持多继承吗?

1)不支持,只支持单继承—一个类只能有一个父类;
2)java中的接口支持多继承,即一个子接口可以有多个父接口。
类实现接口是为了扩展其对象的功能,一个子接口有多个父接口说明它扩展了多种功能,当一个类实现子接口时,类就扩展了各个父类相应的功能。

1.8 接口和抽象类的区别☆(待总结)

java提供和支持创建【抽象类】和【接口】,它们的实现有共同点。
不同点:
1)抽象类:声明方法的存在而不实现方法的类,它用于创建一个 要体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况;
①接口时绝对抽象的,不可以被实例化;抽象类也不可以被实例化,但是如果它包含main方法的话是可以被调用的;
可以创建一个抽象类类型的变量(引用类型)指向其子类的一个实例;
不能有抽象构造函数或抽象静态方法。
②接口中声明的变量默认都是static final的,抽象类可以包含非final的变量;
③接口中所有的方法隐含的都是抽象的,默认是public的,抽象类可以同时包含抽象方法和非抽象方法,可以是private或protected或public的;
②类可以实现多个接口,但是只能继承一个抽象类;
只有当类声明为抽象类的时候,才可以不实现其父抽象类和接口中声明的所有方法;抽象类可以在不提供接口方法实现的情况下实现接口;

1.9 Comparable和Comparator接口作用及区别

1)Java提供Comparable接口,只包含一个compareTo()方法。该方法给两个对象排序,它返回负数、0、正数来表明输入对象小于、等于、大于调用该方法的对象;
2)Java提供Comparator(),包含compare()和equals()两个方法。compare给两个参数排序,返回负数、0、正数表名第一个参数小于、等于、大于第二个参数;equals()需要一个对象作为输入参数,用于判断输入的对象与当前的Comparator是否相等,只有当输入参数也是一个Comparator且其输入参数和当前Comparator的排序结果相同时才返回true
ComparatorA的输入参数a,b返回x;
ComparatorB的输入参数c,d返回x;
则ComparatorA.equals(ComparatorB);

1.10 Static Nested Class和Inner Class的不同

外部类就是包含这个内部类的类。
1)前者是被声明为静态(static)的内部类,可以不依赖于外部类的实例被实例化。该内部类的成员可以是静态的(static),也可以是动态的(instance)。其静态成员方法只能访问外部类的静态成员,而不能访问外部类的动态成员;而其动态成员可以访问外部类的所有成员。可以实现static、protected、private等访问修饰
2)普通的内部类,只能在外部类实例化之后才能实例化。一般只有public和package的访问修饰;
3)内部类可以引用它包含的类成员吗?有何限制?(待总结)

1.11 对象的传递

1)对象作为方法的参数,在方法中改变对象属性后返回该对象,这是值传递还是引用传递?
答:是值传递,java只有值传递;当一个对象实例作为参数传递到方法中,传递的其实就是该对象实例的引用(内存地址值),方法可以通过该引用改变对象的内容,但对象的引用是永远不会改变的。

1.12 Java接口和C++虚类的异同

由于Java不支持多继承,而有可能某个类或对象要使用的方法或属性分别在几个类或对象里面,现有的单继承机制就不能满足要求。与继承相比,接口 有更高的灵活性,因为接口中没有任何实现代码 ,当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是 public static,所有方法默认情况下是 public。一个类可以实现多个接口。

1.13 构造函数、构造函数重载、复制构造函数

1)当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java 编译器会为这个类创建一个默认的构造函数。
2)Java 中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有 它自己 唯一的参数列表。
3)Java 不支持像 C++中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java 不会【创建默认的复制构造函数】。
拷贝构造函数,又称复制构造函数,是一种特殊的构造函数,它由编译器调用来完成一些【基于同一类的其他对象的】构建及初始化,其形参必须是引用。

2.Query接口

1) Query接口的list方法和iterate方法有什么区别?
①list()方法无法利用一级缓存和二级缓存(对缓存只写不读),它只能在开启查询缓存的前提下使用查询缓存;不会引起 N+1 查询问题;
2)iterate()方法可以充分利用缓存,如果目标数据只读或者读取频繁,使用 iterate()方法可以减少性能开销;会引起 N+1 查询问题;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值