Java面试复习1 java面向对象和javase语法
声明:本面试复习都基于一本未署名的Java面试宝典所述,根据自己的理解写出了这一专栏的复习博客
-
java是一门面向对象的语言,他主要有三大特性:继承,封装,多态,抽象(第四特性,通常是三大,但如果有问到四,说出此特性就可以了)
- 继承:即从已有类(父类,又称为超类,基类)得到继承过来的信息并且根据此信息创建新类(子类,又称为派生类)的过程。继承让变化中的软件系统有了一定的延续性,同时也是封装程序中可变因素的重要手段。
- 封装:就是将数据和操作数据的方法绑定起来,对数据的访问只能通过已经定义的接口,比如说,方法就是对实现细节操作的一种封装,而类,则是对实现众多方法和众多数据的封装,封装就是将各种细节都隐藏化,只向外界要访问此数据或者方法的用户提供一个最简单的编程接口。
- 多态:是指允许不同的子类对象对同一消息做出不同的响应,简单来说,就是当外界调用同一个方法时,由于在不同子类中,对同一继承自父类的方法有不同情况下的重写,因此返回的结果是不尽相同的(这是属于运行时的多态性)。而在一个类的内部实现多个同一命名的方法,但对参数是有要求的(参数的个数不同,或者参数的类型不同),由于参数的不同,从而会有多种情况下的结果,这称为重载(属于编译时的多态性)。因此我们可以知道,要实现多态性需要两个步骤:一是类继承下的方法重写,二是父类的类型引用引用子类类型的对象,这样就会产生多态。
比如说:A类是B类的父类 Public A a = new B();
4.抽象:抽象就是将一类对象的共同特征总结出来构造类的全过程,包括数据抽象和行为抽象两个方面,抽象只关心对象有哪些属性个行为,并不关注这些行为的细节,所以抽象类中的方法都是不用写结构的,诸如接口,或者抽象类都是在实现或者继承他们的类的重写方法中写具体的方法实现。
-
访问权限的修饰符所能访问到的地方
-
clone对象,通过clone()方法实现。
简单理解就是,当需要创建一个和已有对象完全相同的对象时,我们在改动这个新对象的同时,不希望原有对象被改动,那普通的p2 = p1 作为一种对对象地址的引用显然是不能够满足我们这种需求的,这时我们需要通过在定义实体类的时候重写clone()方法来实现创建一个全新的对象,但是并没有和原有对象处于同一个地址值下,于是我们对于新对象的修改就不会影响原有对象。具体的定义如下:Person p1 = new Person(18,"王五"); Person p2 = (Person) p1.clone();
这时我们便创建了一个新的对象P2,但是具体的属性都与P1相同,除了地址值,不是引用关系。但是问题又来了,P1中的属性18作为一个基本类型的数据,可以实现拷贝,但是String类型根本上讲还是一种引用,那这个时候不是又相同了,于是就有浅拷贝和深拷贝的概念,图解可能更清晰。
前者是浅拷贝,后者是深拷贝。我们不难看出它的区别。而clone()方法在实现的时候就是浅拷贝的。
深拷贝怎么实现呢?
-
goto const Java中的关键字,也是保留字,目前版本的Java中并没有使用。
其他关键字
-
&和&&的区别。
简单来说&符号两边都运算,而&&左边为真,则右边运算,左边为假,右边不运算,直接返回Boolean表达式的结果是假。
举例说就是判断登录操作的账号密码时username!= null&&username.equals("");
两边不能交换位置,更不能使用&,第一个条件不为空的时候,根本没法对字符串用equals方法比较,否则会报错,产生空指针异常。
当然不仅仅是&和&&,|和||也是一样的道理。 -
java中如何跳出多重嵌套的循环
使用label标签标记想要跳出的循环,break label标签名;
但是要尽量避免使用,因为可能根据所写代码的不同产生许多未知的作用。label1: { …… label2: { …… label3: { …… break label2; …… } } }
-
两个对象值相同(x.equals(y) == true),但是可以拥有不同的hashcode,正确与否?
答案:错误
equals方法返回值为true的时候,hashcode也必定相同。但是当hashcode值相同时,却不一定会得到equals方法返回值为true。
-
是否可以继承String类?
答案:不可以。因为String类是final修饰的类,这样的类都不可以被继承。
-
当一个对象被当做参数传递到一个方法后,此方法可以改变这个对象的属性,并可以返回变化后的结果,那么这里到底是值传递还是引用传递?
答案 :值传递。Java语言的方法调用只支持参数的值传递。当一个对象被当做参数传递到方法中时,参数的值就是对象的引用,这一点我们可以在实际开发中深有体会,传递的是地址值。
-
重载和重写的区别。
这一点在之前写Java的多态性时有过简单的叙述。
这里详细叙述:
重载:
1. 方法名必须一致, 但是参数列表的顺序、类型、个数不同(或者关系)。
2. 重载与方法的返回值无关,存在于父类子类和同类中。
3. 可以泡出不同的异常,可以有不同的修饰符。
重写:
1. 方法名,参数列表都必须完全相同,返回值类型必须与被重写方法的返回值一致。
2. 构造方法不能被重写,生命为final的方法不能被重写,声明为static的方法也不能被被重写,但是可以被再次声明。
3. 访问权限不能比父类中的被重写方法更低,只能更高,如private->public可取,降低不可取。
4. 重写的方法能够抛出任何的非强制异常(也叫非强制异常),无论被重写的方法是否抛出异常。但是重写的方法不能抛出心得强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。(这一点在异常的学习中就会深有体会) -
为什么函数不能根据返回类型来区分重载?(HUAWEI面试题)
因为在调用方法的时候我们不能指定调用的返回值类型,于是在调用方法的时候编译器就不知道你调用的是哪一个方法。max();
而重写因为是根据对象调用,就会知道你调用的是哪个类中的方法p1.getname();
-
char类型变量中能不能存储一个汉字,为甚么?
是可以的,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的且唯一的方法),一个char类型占据两个字节(16bit),所以放一个中文是没有问题的。(一个汉字占两个字节)
顺便复习一下各个类型站的字节数。
char类型2字节
boolean类型比较特殊,但是一般情况下认为是一个字节
具体情况比较多可参考链接博客。
https://blog.csdn.net/amoscn/article/details/97377833. -
抽象类和接口有什么异同?
不同
抽象类:
1. 抽象类中可以定义构造器。
2. 可以有抽象方法和具体方法。
3. 接口中的成员全部是public的
4. 抽象类中可以定义成员变量。
5. 有抽象方法的类必须是抽象方法,但是抽象方法中未必要一定有抽象类的存在。
6. 抽象类中可以包含静态方法。
7. 一个类智能继承一个抽象类。
接口:
1. 接口中不能定义构造器。
2. 接口中的方法都是抽象方法。
3. 抽象类中成员可以是默认,public,private,protected
4. 接口中的成员变量实际上都是常量。
5. 接口中不能有静态方法。
6. 一个类可以实现多个接口。
相同
1. 都不能够实例化。
2. 可以将抽象类和接口类型作为引用类型
3. 一个类如果继承或者实现了抽象方法或者接口需要对其中的所有抽象方法进行重写,否则该类仍然得是个抽象类。 -
抽象方法是否可同时是静态的(static),本地方法(native),可被synchronized?
答案:都不能。
因为抽象方法需要实现子类重写,而static的方法只能适用于本类,矛盾;
本地方法是由本地代码实现的方法,抽象方法并没有实现,矛盾;
synchronized与实现的细节有关,而抽象方法中完全没有设计实现的细节,矛盾。 -
阐述静态变量和实例变量的区别?
静态变量: 是指被static修饰的变量,也称为类变量,只适用于本类,不属于类的任何一个对象,一个类不论创建多少个对象,静态变量在内存中只有一个拷贝。
实例变量: 必须依存于某一个实例,需要首先创建对象然后才能通过对象访问到他,静态变量可以实现让多个对象共享内存。 -
== 和equals的区别?
一个是方法,一个是运算符
==, 如果比较的是基本数据类型,则比较的是数值是否相等;而如果比较的是引用数据类型,比如String 则比较的是对象引用的地址值。
equals, 用来比较方法两个对象是否相等。基本数据类型是不能通过它进行比较的,而如果没有对equals方法进行重写的时候,则比较的是引用类型的变量所指向的对象的地址。 -
break和continue的区别。
两个都是用来控制循环的关键字。
break是用于安全结束整个循环,他所在的循环中,他之后的语句不再执行。
简单例子就是结束整个for循环(i<5)。break(i=1),直接结束。
continue 则是跳过本次循环,执行下次循环。
简单例子就是for循环(i<5)中结束当前条件下的循环(i=3),开始下个条件下的循环(i=4)。 -
String s = “Hello”;s= s+“world”;代码执行后,原始String对象s中的内容是否发生了改变?
答案:没有。因为String类是一个不可变类,因此它的所有对象都是不可变对象,这段代码中的s第一行指向了一个String对象s,内容是"Hello",之后第二行操作之后,这时s重新指向了一个新的String对象,内容是"Helloworld",原来的对象还在内存(这里我的理解是,这个内存是字符串常量池)中存在,但是s的指针不再指向它了。这里让我联想到了字符串常量池的概念,String对象地址所指向的地方为字符串常量池,而如果不new的话是不会再内存中分配空间的。
可以这么理解 String name = "name";String name = new String("name");
这两句代码可以说从结果上看都是一样的,都是声明了一个String类型的name,name的值为"name",
但是前者在声明的时候字符串常量池中没有"name"这个具体的字符串,因此他需要在字符串常量池中创建一个"name"字符串,然后再将这个字符串交给所声明的String类型的name,
而后者作为同个代码块中的代码,在声明的时候,new了一个内存空间,于是它的name指向的是内存空间中的地址值,而内存空间中并不能创建字符串,因此内存空间中还需要指向字符串常量池中找对应的字符串,
本例中字符串常量池中存在与它相对应的值,因此在字符串常量池的常量池地址上(这个字符串常量池的地址是我自己构想的,并不准确,只是一种记忆方式,不要借鉴)是相同的。所以==运算符为true,equals为false。
对字符串常量池更具体的分析可以参考以下博客。
https://blog.csdn.net/qq_34490018/article/details/82110578