接口中不能有构造方法,抽象类中可以有。抽象类中构造方法作用:初始化抽象类的成员;为继承它的子类使用
定义在同一个包(package)内的类是可以不经过import而直接相互使用
final修饰的方法可以被重载 但不能被重写
从设计层面来说,抽象类是对类的抽象,是一种模板设计,接口是行为的抽象,是一种行为的规范。
- 进入DEAD的线程,它还可以恢复,GC不会回收
静态变量
下列代码输出什么
class HasStatic{
private static int x = 100;
public static void main(String args[ ]){
HasStatic hs1 = new HasStatic();
hs1.x++;
HasStatic hs2 = new HasStatic();
hs2.x++;
hs1=new HasStatic();
hs1.x++;
HasStatic.x--;
System.out.println( "x=" +x);
}
}
答案:102
判断:
可以用违例(Exception)来抛出一些并非错误的消息,可以,并非错误的消息。比如我自定义一个异常,若一个变量大于10就抛出一个异常,这样就对应了B选项说的情况,我用抛出异常说明这个变量大于10,而不是用一个函数体(函数体内判断是否大于10,然后返回true或false)判断,因为函数调用是入栈出栈,栈是在寄存器之下的速度最快,且占的空间少,而自定义异常是存在堆中,肯定异常的内存开销大!所以B对。
javac
构造器
易错:超易错,
下面代码将在哪一处报错:
public class MyClass {
long var;
public void MyClass(long param) { var = param; }//(1)
public static void main(String[] args) {
MyClass a, b;
a =new MyClass();//(2)
b =new MyClass(5);//(3)
}
}
答案:3)
构造方法就是:public 类名, 没有方法修饰符
所以 (1) 处就是一个普通方法
所以该类没有带参数构造方法 ,编译报错
易错2:
下面代码将输出什么
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);
}
}
答案:报错
静态变量只能在类主体中定义,不能在方法中定义
- 子类不但可以继承父类的无参构造函数,也可以继承父类的有参构造函数。
答案:x
构造函数不能被继承,构造方法只能被显式或隐式的调用。
如果说有参构造可以被继承,那么在子类中有参构造就可以被重写;那么就无法通过父类的有参构造创建对象了;所以有参构造不能被继承。
1.构造函数不能继承,只是调用而已;
2.若父类没有无参构造函数,则创建子类时,不能编译;除非在构造函数代码体中第一行,必须是第一行显示调用父类的有参构造函数;
3.若父类中没有任何构造函数,则系统会默认有一个无参构造函数
如果父类中只定义了有参数构造方法,jvm就不会隐式为父类创建无参数构造,那么,你在创建子类继承父类时,你的子类就必须调用父类中任何一个有参数构造进行初始化才行,如果,在你的子类中仅仅写个无参数构造,那么编译不通过
访问权限
- 访问权限控制从最大权限到最小权限依次为:public、 包访问权限、protected和private 。
答案:错
public、protected、 包访问权限和private 。
下面代码运行结果是什么
public class Arraytest{
int a[] = new int[6];
public static void main ( String arg[] ) {
System.out.println ( a[0] );
}
}
答案: 编译错误
在static方法中是不能访问非静态变量 a 的,需要将 a 声明为static,答案才会是 0 ,否则是编译出错
匿名内部类
匿名内部类可以看这里,
答案:✓
匿名内部类的创建格式为: new 父类构造器(参数列表)|实现接口(){
//匿名内部类的类体实现
}
使用匿名内部类时,必须继承一个类或实现一个接口
匿名内部类由于没有名字,因此不能定义构造函数
匿名内部类中不能含有静态成员变量和静态方法
Byte
下面代码输出什么:
public class Test2
{
public void add(Byte b)
{
b = b++;
}
public void test()
{
Byte a = 127;
Byte b = 127;
add(++a);
System.out.print(a + " ");
add(b);
System.out.print(b + "");
}
}
答案:-128 127
解析:
包装类的值是final修饰不可变的,无论是++b还是b++都创建了一个新对象,那么作为参数传递时,形参和实参不会指向一个地址。也就是说,即使add() 方法中不是b = b++;这样没有意义的代码,传入参数的值也不会改变。
byte类型取值范围为-128~127,在a变量进行++a运算时,会导致a变为-128,这是因为整数在内存中使用的是补码的形式表示,最高位是符号位,0表示正数,1表示负数,加一导致补码进位,符号位变为1.
因此,本题正确输出为-128 127
左移右移
>>表示右移,如果该数为正,则高位补0,若为负数,则高位补1;
>>>表示无符号右移,也叫逻辑右移,即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0
运算符“>>”执行算术右移,它使用最高位填充移位后左侧的空位。
右移的结果为:每移一位,第一个操作数被2除一次,移动的次数由第二个操作数确定。
逻辑右移或叫无符号右移运算符“>>>“只对位进行操作,没有算术含义,它用0填充左侧的空位。
算术右移不改变原数的符号,而逻辑右移不能保证这点。
移位运算符约简其右侧的操作数,当左侧操作数是int类型时,右侧以32取模;当左侧是long类型时,右侧以64取模。
>> 右移 高位补符号位
>>> 右移 高位补0
~~~ 逻辑左移时,最高位丢失,最低位补0;~~~
逻辑右移时,最高位补0,最低位丢失;
算术左移时,依次左移一位,尾部补0,最高的符号位保持不变。
算术右移时,依次右移一位,尾部丢失,符号位右移后,原位置上复制一个符号位;
循环左移时,将最高位重新放置最低位
循环右移时,将最低位重新放置最高位
例如:
1010100010101
~~逻辑左移一位结果为 0101000101010~~
逻辑右移一位结果为 0101010001010
算术左移一位结果为 1101000101010
算术右移一位结果为 1101010001010
循环左移一位结果为 0101000101011
循环右移一位结果为 1101010001010
总结的比较好的
java跨平台运行
write once,run everywhere 指的是编译后的字节码可以跨平台执行,也就是class文件,而不是Java源文件
is-a has-a like-a
is-a:继承关系 has-a:从属关系 like-a:组合关系
抽象类表示的是 is-a 关系;
接口表示的是 like-a 关系;
易错
package algorithms.com.guan.javajicu;
public class Inc {
public static void main(String[] args) {
Inc inc = new Inc();
int i = 0;
inc.fermin(i);
i= i ++;
System.out.println(i);
}
void fermin(int i){
i++;
}
}
答案:0
第二弹
下面代码编译会报错吗?
public class Person{
static int arr[] = new int[5];
public static void main(String a[]){
System.out.println(arr[0]);
}
}
答案:不会,初始化的时候会赋初始值0,5个0
接口
接口中只能有静态的不能被修改的成员,也就是必须是static final的
如果是Java 7以及以前的版本,那么接口中可以包含的内容有:1. 常量;2. 抽象方法
如果是Java 8,还可以额外包含有:3. 默认方法;4. 静态方法
如果是Java 9,还可以额外包含有:5. 私有方法
4.
在JAVA中,假设A有构造方法A(int a),则在类A的其他构造方法中调用该构造方法和语句格式应该为()
A、this.A(x)
B、this(x)
C、super(x)
D、A(x)
解析:
答案:B
this的作用其中一个就是在一个构造方法中调用另一个构造方法,格式为this(参数); super是调用父类的方法 比如super.start();
A(a)这种形式是在new一个类时使用。
基类 导出类
基类就是父类,也叫超类。导出类就是子类,也叫派生类。
threadLocal
关于ThreadLocal类 以下说法正确的是
A.ThreadLocal继承自Thread
B.ThreadLocal实现了Runnable接口
C.ThreadLocal重要作用在于多线程间的数据共享
D.ThreadLocal是采用哈希表的方式来为每个线程都提供一个变量的副本
E.ThreadLocal保证各个线程间数据安全,每个线程的数据不会被另外线程访问和破坏
答案:de
1、ThreadLocal的类声明: public class ThreadLocal 可以看出ThreadLocal并没有继承自Thread,也没有实现Runnable接口。所以AB都不对。 2、ThreadLocal类为每一个线程都维护了自己独有的变量拷贝。每个线程都拥有了自己独立的一个变量。 所以ThreadLocal重要作用并不在于多线程间的数据共享,而是数据的独立,C选项错。 由于每个线程在访问该变量时,读取和修改的,都是自己独有的那一份变量拷贝,不会被其他线程访问, 变量被彻底封闭在每个访问的线程中。所以E对。 3、ThreadLocal中定义了一个哈希表用于为每个线程都提供一个变量的副本: 所以D对。
servlet生命周期
Servlet生命周期分成3个阶段:
1)初始化阶段:调用init方法
2)响应客户请求:调用service
3)终止:调用destory方法
初始化阶段:在下列时刻servlet容器装载servlet
1 servlet容器启动时,自动装载某些servlet
2 在servlet容器启动后,客户首次向servlet发送请求
3 servlet类文件被更新之后,重新装载servlet
Servlet被装载之后,servlet容器创建一个servlet’对象并调用servlet的init方法,在servlet生命周期内,init方法只能被调用一次。servlet工作原理:客户端发起一个请求,servlet调用service方法时请求进行响应,service对请求的方式进行了匹配,选择调用dopost或者doget等这些方法,然后进入对应方法中调用逻辑层的方法,实现对客户的响应。
响应客户请求:对于用户到达servlet的请求,servlet容器会创建特定于该请求的servletrequest和servletresponse对象,然后调用servlet的service方法,service方法从servletrequest对象中获取客户请求的信息,处理该请求,并且通过servletresponse对象向客户端返回响应信息。
终止:当web应用终止或者servlet容器终止或servlet容器重新装载servlet新实例时,servlet容器会调用servlet对象的destory方法,在destory方法中可以释放servlet占用的资源
易错题
下面输出什么:
Boolean flag = false;
if (flag = true)
{
System.out.println("true");
}
else
{
System.out.println("false");
}
答案: true
看清,flag = true
不是 ==
第二
下面哪段代码插入进来不会报错
interface Com{
int M=200;
int f();
}
class ImpCom implements Com{
【代码】
}
>
A. public int f(){return 100+M;}
B. int f(){return 100;}
C. public double f(){return 2.6;}
D. public abstract int f();
答案:A
B选项没有修饰符,不知道是public default 还是什么
1、必须实现接口中所有的方法。
在实现类中实现接口时,方法的名字、返回值类型、参数的个数及类型必须与接口中的完全一致,并且必须实现接口中的所有方法。
2、接口实现类相当于子类,子类的访问权限是不能比父类小的。
接口中所有方法默认都是public,至于为什么要是public,原因在于如果不是public,那么只能在同个包下被实现,可访问权限就降低很多了,那么在实现类中,实现的类相当于子类,子类的访问权限是不能比父类小的,而在java中一个类如果没有权限的修饰符,默认是friendly(同一个包内的其它类才可访问),所以在实现类中一定要写public
类型转换
语句1,2,3,4哪几个是错的?
byte b1=1,b2=2,b3,b6,b8;
final byte b4=4,b5=6,b7;
b3=(b1+b2); /*语句1*/
b6=b4+b5; /*语句2*/
b8=(b1+b4); /*语句3*/
b7=(b2+b5); /*语句4*/
System.out.println(b3+b6);
答案: 1,3,4
1、所有的byte,short,char型的值将被提升为int型;
2、如果有一个操作数是long型,计算结果是long型;
3、如果有一个操作数是float型,计算结果是float型;
4、如果有一个操作数是double型,计算结果是double型;
5、被fianl修饰的变量不会自动改变类型,当2个final修饰相操作时,结果会根据左边变量的类型而转化。
--------------解析--------------
语句1错误:b3=(b1+b2);自动转为int,所以正确写法为b3=(byte)(b1+b2);或者将b3定义为int;
语句2正确:b6=b4+b5;b4、b5为final类型,不会自动提升,所以和的类型视左边变量类型而定,即b6可以是任意数值类型;
语句3错误:b8=(b1+b4);虽然b4不会自动提升,但b1仍会自动提升,所以结果需要强转,b8=(byte)(b1+b4);
语句4错误:b7=(b2+b5); 同上。同时注意b7是final修饰,即只可赋值一次,便不可再改变。
反射
getDeclaredField:查找该Class所有声明属性(静态/非静态),但是他不会去找实现的接口/父类的属性
getField:只查找该类public类型的属性,如果找不到则往上找他的接口、父类,依次往上,直到找到或者已经没有接口/父类
public Object getName1() throws NoSuchFieldException, IllegalAccessException {
return User.class.getDeclaredField("name").get(null);
}
public Object getName2() throws NoSuchFieldException, IllegalAccessException {
return User.class.getField("name").get(null);
}
public Object getName3() throws NoSuchFieldException, IllegalAccessException {
User user=new User(); return user.getClass().getField("name").get(user);
}
public Object getName4() throws NoSuchFieldException, IllegalAccessException {
User user=new User(); return user. getClass().getDeclaredField("name").get (user);
}
get方法是获得user对象下前面指定好的属性的值,而获取static属性时get()括号里的对象可以写成null
多态
下面代码输出什么?
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));
}
}
答案:两个150
多态绑定机制:
实例方法与引用变量所引用的对象的方法绑定;
静态方法与引用变量所声明的类型的方法绑定;
成员变量(实例变量、静态变量)与引用变量所声明的类型的成员变量绑定。
在这道题目中,由于都是实例方法,所以与所引用的对象的方法绑定。(new 后跟引用对象)
涉及转型的题目,分为向上或者向下转型。 关键的来了,不论向上或者向下转型,都是一句话,“编译看左边,运行看右边”。也就是编译时候,会看左边引用类型是否能正确编译通过,运行的时候是调用右边的对象的方法。A a=new B();这是向上转型。B b=(B)a;这是向下转型。但是,A a =new A();B b= (B)a;此时会报错。 就本题来说,编译时候会发现左边满足条件所以编译通过,运行时候又会调用右边也就是 class B 的方法,所以答案都是150。
类
下面关于变量及其范围的陈述哪些是不正确的()
A。实例变量是类的成员变量
B。实例变量用关键字static声明
C。在方法中定义的局部变量在该方法被执行时创建
D。局部变量在使用前必须被初始化
答案:BC
解析:
类的成员变量包括实例变量和类变量(静态变量),成员方法包括实例方法和类方法(静态方法)
C.方法中的局部变量在方法被调用加载时开始入栈时创建,方法入栈创建栈帧包括局部变量表操作数栈,局部变量表存放局部变量,并非在执行该方法时被创建,C错误
D.局部变量被使用前必须初始化,否则程序报错。D正确
finally
下面输出什么
public class Demo {
public static String sRet = "";
public static void func(int i)
{
try
{
if (i%2==0)
{
throw new Exception();
}
}
catch (Exception e)
{
sRet += "0";
return;
}
finally
{
sRet += "1";
}
sRet += "2";
}
public static void main(String[] args)
{
func(1);
func(2);
System.out.println(sRet);
}
}
答案:1201
解答:
第一步,func(1),if条件不成立,不抛出异常,catch不运行,final运行,拼串得到“1”,程序继续往下走,拼串得到“12”。 第二步,fun(2),if条件成立,抛出异常,catch捕获异常,运行catch里面代码,拼串得到“120”,虽然有return,但是不管出不出异常,final里代码必须执行,执行final,拼串得到“1201”,然后return结束。所以最终结果“1201”
流
下列流当中,属于处理流的是:()
A.FilelnputStream
B.lnputStream
C.DatalnputStream
D.BufferedlnputStream
按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。
节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.
处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接。
JAVA常用的节点流:
文 件 FileInputStream FileOutputStrean FileReader FileWriter 文件进行处理的节点流。
字符串 StringReader StringWriter 对字符串进行处理的节点流。
数 组 ByteArrayInputStream ByteArrayOutputStreamCharArrayReader CharArrayWriter 对数组进行处理的节点流(对应的不再是文件,而是内存中的一个数组)。
管 道 PipedInputStream PipedOutputStream PipedReaderPipedWriter对管道进行处理的节点流。
常用处理流(关闭处理流使用关闭里面的节点流)
缓冲流:BufferedInputStrean BufferedOutputStream BufferedReader BufferedWriter 增加缓冲功能,避免频繁读写硬盘。
转换流:InputStreamReader OutputStreamReader 实现字节流和字符流之间的转换。
数据流 DataInputStream DataOutputStream 等-提供将基础数据类型写入到文件中,或者读取出来.
流的关闭顺序
一般情况下是:先打开的后关闭,后打开的先关闭
另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b。例如,处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b
可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法。
servlet体系结构