1.下列程序执行后结果为( )
class A {
public int func1(int a, int b) {
return a - b;
}
}
class B extends A {
public int func1(int a, int b) {
return a + b;
}
}
public class ChildClass {
public static void main(String[] args) {
A a = new B();
B b = new B();
System.out.println("Result=" + a.func1(100, 50));
System.out.println("Result=" + b.func1(100, 50));
}
}
-
Result=150 Result=150
-
涉及转型的题目,分为向上或者向下转型。
关键的来了,不论向上或者向下转型,都是一句话,“编译看左边,运行看右边”。也就是编译时候,会看左边引用类型是否能正确编译通过,运行的时候是调用右边的对象的方法。 此题考查的是多态。
-
对于多态,可以总结它为:
一、使用父类类型的引用指向子类的对象;
二、该引用只能调用父类中定义的方法和变量;
三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
多态的3个必要条件:
1.继承 2.重写 3.父类引用指向子类对象。
向上转型: Person p = new Man() ; //向上转型不需要强制类型转化
向下转型: Man man = (Man)new Person() ; //必须强制类型转化
2.对于以下代码段,4个输出语句中输出true的个数是( )。
class A{}
class B extends A{}
class C extends A{}
class D extends B{}
public class Test {
public static void main(String[] args) {
A obj = new D();
System.out.println(obj instanceof B);
System.out.println(obj instanceof C);
System.out.println(obj instanceof D);
System.out.println(obj instanceof A);
}
}
- true
false
true
true - C直接继承自A,obj的实际类型为D,和C没有关系。所以obj instanceof C 输出false。
3.以下代码将打印出
public static void main(String args[]) {
List Listlist1 = new ArrayList();
Listlist1.add(0);
List Listlist2 = Listlist1;
System.out.println(Listlist1.get(0) instanceof Integer);
System.out.println(Listlist2.get(0) instanceof Integer);
}
-
true true
-
collection类型的集合(ArrayList,LinkedList)只能装入对象类型的数据,该题中装入了0,是一个基本类型,但是JDK5以后提供了自动装箱与自动拆箱,所以int类型自动装箱变为了Integer类型。编译能够正常通过。
将list1的引用赋值给了list2,那么list1和list2都将指向同一个堆内存空间。instanceof是Java中关键字,用于判断一个对象是否属于某个特定类的实例,并且返回boolean类型的返回值。显然,list1.get(0)和list2.get(0)都属于Integer的实例
4.在类设计中,类的成员变量要求仅仅能够被同一package下的类访问,请问应该使用下列哪个修饰词()
-
不需要任何修饰词
5.在Java中,以下关于方法重载和方法重写描述正确的是?
-
方法重写的返回值类型必须相同或相容。 重载(overload):只要方法名 一致 ,其他(参数列表、返回值)怎么折腾随便。 重写(overriding):只有实现的功能代码 不一致 ,其他的(函数名、参数列表、返回值类型)必须都一致。 目前的问题:父类的功能无法满足子类的需求。 方法重写的前提: 必须要存在继承的关系。 方法的重写: 子父类出了同名的函数,这个我们就称作为方法的重写。 什么是时候要使用方法的重写:父类的功能无法满足子类的需求时。 方法重写要注意的事项: 1.方法重写时, 方法名与形参列表必须一致。 2.方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。 3.方法重写时,子类的返回值类型必须要小于或者 等于父类的返回值类型。 4.方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。 Exception(最坏) RuntimeException(小坏) 方法的重载:在一个类中 存在两个或者两个 以上的同名函数,称作为方法重载。 方法重载的要求 1. 函数名要一致。 2. 形参列表不一致(形参的个数或形参 的类型不一致) 3. 与返回值类型无关。
6.默认类型等价表示是哪一项:
public interface IService {String NAME="default";}
-
public static final String NAME="default";
- 接口中的变量默认是public static final 的,方法默认是public abstract 的
7.以下代码对其执行后,NumberList里的元素依次为:
public static void main(String args[]) {
List<Integer> NumberList = new ArrayList<Integer>();
NumberList.add(2);
NumberList.add(4);
NumberList.add(1);
NumberList.add(3);
NumberList.add(5);
for (int i = 0; i < NumberList.size(); ++i) {
int v = NumberList.get(i);
if (v % 2 == 0) {
NumberList.remove(v);
}
}
System.out.println(NumberList);
}
-
会出现越界情况
-
这题主要考察两点:
1.ArrayList删除元素后,剩余元素会依次向前移动,因此下标一直在变,size()也会减小;
2.remove()方法调用的是remove(int index),而不是remove(Object o),因此删除的是index索引处的元素;
该题具体流程:1.i=0,v=2,remove(2)删除掉了元素1,因此NumberList剩余元素为【2,4,3,5】;
2.i=1,v=4,remove(4),此时线性表中只有四个元素,不可能删除索引为4的元素,因此会报数组下标越界异常。
8.在一个基于分布式的游戏服务器系统中,不同的服务器之间,哪种通信方式是不可行的()?
-
管道
-
对于管道,有下面这几种类型:
①普通管道(PIPE):通常有两种限制,一是单工,即只能单向传输;二是血缘,即常用于父子进程间(或有血缘关系的进程间)。
②流管道(s_pipe):去除了上述的第一种限制,实现了双向传输。
③命名管道(name_pipe):去除了上述的第二种限制,实现了无血缘关系的不同进程间通信。
显然,要求是对于不同的服务器之间的通信,是要要求全双工形式的,而管道只能是半双工,虽然可以双向,但是同一时间只能有一个方向传输,全双工和半双工的区别可以如下图示理解:
9.What will be printed when you execute the following code?
class C {
C() {
System.out.print("C");
}
}
class A {
C c = new C();
A() {
this("A");
System.out.print("A");
}
A(String s) {
System.out.print(s);
}
}
class Test extends A {
Test() {
super("B");
System.out.print("B");
}
public static void main(String[] args) {
new Test();
}
}
-
CBB
-
初始化过程是这样的:
1.首先,初始化父类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
2.然后,初始化子类中的静态成员变量和静态代码块,按照在程序中出现的顺序初始化;
3.其次,初始化父类的普通成员变量和代码块,在执行父类的构造方法;
4.最后,初始化子类的普通成员变量和代码块,在执行子类的构造方法;
(1)初始化父类的普通成员变量和代码块,执行 C c = new C(); 输出C
(2)super("B"); 表示调用父类的构造方法,不调用父类的无参构造函数,输出B
(3) System.out.print("B");
所以输出CBB
10.Test.main()函数执行后的输出是( )
class Test {
public static void main(String[] args) {
System.out.println(new B().getValue());
}
static class A {
protected int value;
public A (int v) {
setValue(v);
}
public void setValue(int value) {
this.value= value;
}
public int getValue() {
try {
value ++;
return value;
} finally {
this.setValue(value);
System.out.println(value);
}
}
}
static class B extends A {
public B () {
super(5);
setValue(getValue()- 3);
}
public void setValue(int value) {
super.setValue(2 * value);
}
}
}
-
22 34 17
-
思考和解决这个题的主要核心在于对java多态的理解。个人理解时,执行对象实例化过程中遵循多态特性 ==> 调用的方法都是将要实例化的子类中的重写方法,只有明确调用了super.xxx关键词或者是子类中没有该方法时,才会去调用父类相同的同名方法。
Step 1: new B()构造一个B类的实例
此时super(5)语句调用显示调用父类A带参的构造函数,该构造函数调用setValue(v),这里有两个注意点一是虽然构造函数是A类的构造函数,但此刻正在初始化的对象是B的一个实例,因此这里调用的实际是B类的setValue方法,于是调用B类中的setValue方法 ==> 而B类中setValue方法显示调用父类的setValue方法,将B实例的value值设置为2 x 5 = 10。
紧接着,B类的构造函数还没执行完成,继续执行setValue(getValue()- 3) // 备注1语句。先执行getValue方法,B类中没有重写getValue方法,因此调用父类A的getValue方法。这个方法比较复杂,需要分步说清楚:
- 调用getValue方法之前,B的成员变量value值为10。
- value++ 执行后, B的成员变量value值为11,此时开始执行到return语句,将11这个值作为getValue方法的返回值返回出去
- 但是由于getValue块被try finally块包围,因此finally中的语句无论如何都将被执行,所以步骤2中11这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
- 这里有很重要的一点:finally语句块中 this.setValue(value)方法调用的是B类的setValue方法。为什么?因为此刻正在初始化的是B类的一个对象(运行时多态),就像最开始第一步提到的一样(而且这里用了使用了this关键词显式指明了调用当前对象的方法)。因此,此处会再次调用B类的setValue方法,同上,super.关键词显式调用A的setValue方法,将B的value值设置成为了2 * 11 = 22。
- 因此第一个打印项为22。
- finally语句执行完毕 会把刚刚暂存起来的11 返回出去,也就是说这么经历了这么一长串的处理,getValue方法最终的返回值是11。
-
回到前面标注了 //备注1 的代码语句,其最终结果为setValue(11-3)=>setValue(8)
而大家肯定也知道,这里执行的setValue方法,将会是B的setValue方法。 之后B的value值再次变成了2*8 = 16;Step2: new B().getValue()
B类中没有独有的getValue方法,此处调用A的getValue方法。同Step 1,
- 调用getValue方法之前,B的成员变量value值为16。
- value++ 执行后, B的成员变量value值为17,此时执行到return语句,会将17这个值作为getValue方法的返回值返回出去
- 但是由于getValue块被try finally块包围而finally中的语句无论如何都一定会被执行,所以步骤2中17这个返回值会先暂存起来,到finally语句块执行完毕后再真正返回出去。
- finally语句块中继续和上面说的一样: this.setValue(value)方法调用的是B类的setValue()方法将B的value值设置成为了2 * 17 = 34。
- 因此第二个打印项为34。
- finally语句执行完毕 会把刚刚暂存起来的17返回出去。
- 因此new B().getValue()最终的返回值是17.
-
Step3: main函数中的System.out.println
将刚刚返回的值打印出来,也就是第三个打印项:17
最终结果为 22 34 17。 如果朋友们在看的过程中仍然有疑问,可以亲自把代码复制进去ide,在关键语句打下断点,查看调用方法的对象以及运行时的对象值,可以有更深刻的理解。
11.下列Java代码中的变量a、b、c分别在内存的____存储区存放。
class A {
private String a = “aa”;
public boolean methodB() {
String b = “bb”;
final String c = “cc”;
}
}
-
堆区、栈区、栈区
-
堆区:只存放类对象,线程共享;
方法区:又叫静态存储区,存放class文件和静态数据,线程共享;
栈区:存放方法局部变量,基本类型变量区、执行环境上下文、操作指令区,线程不共享;
12.static修饰的成员不能访问非static修饰的成员。
abstract修饰一个类,这个类肯定可以被继承,但是final类是不能继承的,所以有矛盾,肯定不能同时用。
java中可以有多个重载的main方法,只有public static void main(String[] args){}是函数入口。
public class TestMain{
public static void main(String[] args){
System.out.println("Static main");
new TestMain().main();
}
public void main(){
System.out.println("main");
}
}
13.Given:
public class IfTest{
public static void main(String[]args){
int x=3;
int y=1;
if(x = y)
System.out.println("Not equal");
else
System.out.println("Equal");
}
}
What is the result?
-
An error at line 5 causes compilation to fall.
-
这个题考查两个知识点。
1、Java中,赋值是有返回值的 ,赋什么值,就返回什么值。比如这题,x=y,返回y的值,所以括号里的值是1。
2、Java跟C的区别,C中赋值后会与0进行比较,如果大于0,就认为是true;而Java不会与0比较,而是直接把赋值后的结果放入括号。
14.以下代码执行后输出结果为( )
public class Test
{
public static Test t1 = new Test();
{
System.out.println("blockA");
}
static
{
System.out.println("blockB");
}
public static void main(String[] args)
{
Test t2 = new Test();
}
}
- blockA
blockB
blockA - 静态块:用static申明,JVM加载类时执行,仅执行一次
构造块:类中直接用{}定义,每一次创建对象时执行
执行顺序优先级:静态块>main()>构造块>构造方法
静态块按照申明顺序执行,先执行Test t1 = new Test();
所有先输出blockA,然后执行静态块,输出blockB,最后执行main
方法中的Test t2 = new Test();输出blockA。 -
类的加载顺序。
(1) 父类静态对象和静态代码块
(2) 子类静态对象和静态代码块
(3) 父类非静态对象和非静态代码块
(4) 父类构造函数
(5) 子类 非静态对象和非静态代码块
(6) 子类构造函数
其中:类中静态块按照声明顺序执行,并且(1)和(2)不需要调用new类实例的时候就执行了(意思就是在类加载到方法区的时候执行的)
15.Java的跨平台特性是指它的源代码可以在多个平台运行。(错误)
Java的跨平台特性是因为JVM的存在, 它可以执行.class字节码文件,而不是.java源代码。
Java程序初始化的执行顺序:父类静态变量—>父类静态代码块—>子类静态变量—>子类静态代码块—>父类非静态变量—>父类非静态代码块—>父类构造方法—>子类非静态变量—>子类非静态代码块—>子类构造方法。
16.在使用super 和this关键字时,以下描述正确的是
-
在子类构造方法中使用super()显示调用父类的构造方法,super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
- super()和this()类似,区别是,super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
17.对于这段代码,以下说法正确的是:
public class Test
{
public int x;
public static void main(String []args)
{
System. out. println("Value is" + x);
}
}
-
非静态变量不能够被静态方法引用
- 非静态成员只能被类的实例化对象引用,因此这里在静态方法中访问x会造成编译出错
18.如下代码的输出结果是什么?
public class Test {
public int aMethod(){
static int i = 0;
i++;
return i;
}
public static void main(String args[]){
Test test = new Test();
test.aMethod();
int j = test.aMethod();
System.out.println(j);
}
}
-
编译失败
- 静态变量只能在类主体中定义,不能在方法中定义
19.下面哪几个函数 public void example(){....} 的重载函数?()
-
public void example(int m){...}
-
public int example(int m,float f){...}
-
public int example(){..} (错误)
- java重载的时候以参数个数和参数类型作为区分,方法名相同,返回类型可以相同也可以不同,但不以返回类型作为区分,所以c也是错的,因为c的参数列表和原来的一样。