这一期我们继续介绍Java相关的面试题,这一次还是5道题。下面我们开始一一进行解答。
1.请简要比较接口和抽象类的区别。
①:接口中不能包含任何非抽象方法,但是抽象类可以包含;
②:接口可以实现多继承,抽象类不可以实现多继承;
③:抽象类要被子类继承,接口要被类实现;
④:接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量;
⑤:抽象类可以有构造器,接口不能有构造器。
具体可参照博客链接https://www.cnblogs.com/jmyyyy/p/10960271.html,这里只列出常见的几种区别了。
2.(1)什么是内部类?请简要说说内部类有哪些特点?
(2)什么是静态内部类?其有什么特点?
(1)内部类就是定义在另一个类中内部的类,内部类的特点有:
①:内部类可以访问其外部类的所有属性和方法;
②:外部类无法直接访问内部类的属性和方法,需要实例化才可以;
③:内部类如果和外部类有同名的属性,优先执行内部类的属性;
④:内部类不能定义static的变量。
下面我们写一个简单的例子,加深对内部类的理解。代码如下:
public class Outer {
private int varOuter = 100;
private double x = 20.5;
/**
* 内部类:对于其他类中的类是隐藏的,不能被访问;
* 不能定义static的变量,
* 内部类可以直接访问到外部类的变量,无需实例化;
* 但是外部类想要访问到内部类,需要实例化,
* 如果类不想被其他类使用,可以声明为内部类.
* 内部类如果和外部类有同名的属性,优先执行内部类的属性.
* @author autumn_leaf
*
*/
class Inner {
int varInner = 200; //变量定义
double x = 50.5;//内部变量x
//方法定义
public void showOuter() {
System.out.println(varOuter);//调用外部类的变量
System.out.println(x);//50.5
//20.5
System.out.println(Outer.this.x);//调用外部类的同名属性
}
}
//外部类引用内部类必须要实例化
public void showInner() {
Inner i = new Inner();
System.out.println(i.varInner);//200
i.showOuter();//100
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.showInner();
}
}
(2)静态内部类就是用static标识的内部类,其特点是可以定义静态成员和非静态成员,而非静态内部类只能定义非静态成员。
下面写一个小的例子来简要介绍静态内部类的用法,代码如下:
public class OuterStatic {
private int varOuter = 20;
//内部类可用修饰符:default public private protected
/**
* 定义一个静态内部类,可以定义静态的变量,也可以定义非静态的变量
* 非静态内部类不可以定义static的变量
*/
private static class innerStatic {
static int a;
int varInner = 200;
public void showOuter() {
//静态内部类不能调用外部非static修饰的内容
//System.out.println(varOuter);
//可以调用类中定义的非静态变量
System.out.println(varInner);
}
}
public static void main(String[] args) {
//调用静态内部类
OuterStatic.innerStatic oi = new OuterStatic.innerStatic();
System.out.println(oi.varInner);
System.out.println(oi.a);
//调用非静态内部类
Outer o = new Outer();
Outer.Inner i = o.new Inner();
System.out.println(i.varInner);
i.showOuter();
}
}
3.请简要说说final关键字的用法。
final可以修饰属性、方法以及类,其中:①被修饰的变量不能够被重新赋值,可以在声明时赋值,或者在构造器中赋值;②被修饰的类不能够被继承;③被修饰的方法不能在子类中被覆盖,即不能够被修改。下面写一个简单的例子,代码如下:
public final class FinalDemo {
int a;//默认值为0
static final int b = 1;//必须有值
//如果当前不是final修饰的类,那么可能发生继承关系
//父类被final修饰的方法,子类继承的时候,不能进行覆盖
static final void test() {
System.out.println("不能被修改!");
}
}
4.试比较Object类型与String类型equals方法的区别。
Object类型的equals方法只会比较是否是同一个对象,而String类型的equals方法优先判断是否是同一个对象,若不是同一个对象,则按位进行比较。
下面写一个简单的例子来显示刚刚的说明,代码如下:
public class ObjectSample {
public static void main(String[] args) {
String str1 = new String("haha");
String str2 = "haha";
String str3 = "haha";
System.out.println(str1 == str2);//false str1进行了实例化,所以这里不是同一个对象
System.out.println(str2 == str3);//true 指向同一个对象
//Object类型equals方法只会比较是否是同一对象
//String类型equals方法优先判断是否同一个对象,若不是同对象,则按位进行比较
System.out.println(str1.equals(str2));//true
}
}
结果我已经注释在后面了,下面我们查看一下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;
}
5.尝试对一个邮箱进行检测并抛出异常,要求用户名长度不能超过12位(@符号前面为用户名),@符号后面必须以.com或者.cn结尾,试写出简要的检验代码。
我们首先定义一个异常EmailCheckException,代码如下:
public class EmailCheckException extends Exception{
private static final long serialVersionUID = 1L;
public EmailCheckException(String msg) {
super(msg);
}
}
然后邮箱检测类EmailCheck代码如下:
import java.util.Scanner;
/**
* 邮箱检测
* @author autumn_leaf
*
*/
public class EmailCheck {
public static void checkEmail(String email) throws EmailCheckException {
int unameLen = email.indexOf('@');
int begin = email.indexOf('@');
int end = email.lastIndexOf('@');
int dot = email.indexOf('.');//从开始位置.出现的位置
//用户名长度判断
if(unameLen > 12) {
throw new EmailCheckException("Email用户名长度超过12位!");
}else if(begin != end) {
throw new EmailCheckException("Email中包含多个@!");
}
//未出现@或者@在开头或者@在结尾
else if(begin == -1 || begin == 0 || begin == email.length()-1) {
throw new EmailCheckException("@没有出现或者@位置不对!");
}else if(begin > dot) {
throw new EmailCheckException("@与.出现的位置不对!");
}else if(!email.endsWith(".com") && !email.endsWith(".cn")){
throw new EmailCheckException("邮箱结尾不是.com或者.cn!");
}
}
public static void main(String[] args) {
System.out.println("请输入邮箱:");
Scanner sc = new Scanner(System.in);
String email = sc.nextLine();
try {
checkEmail(email);
} catch (EmailCheckException e) {
e.printStackTrace();
}
System.out.println("操作结束!");
}
}
上述代码中我们先自定义一个邮箱异常类,然后定义一个邮箱检测类,在函数中我们考虑以下几点:
①:用户名长度不能超过12;
②:只能有一个@符号;(没有或者多个@都算错)
③:@符号不能出现在第一个或者最后一个位置;
④:@必须出现在.前面;
⑤:email结尾必须以.com或者.cn结尾。
当这几点都考虑好之后,函数基本就写好了,然后我们在main方法中进行测试就行。
好了,第二期面试题分享就到这里了,我们下期再见!