Ignite

你不知道的Java(二)

2017-07-14

好几天的java基础知识都写在了前两篇里,感觉有些多和杂,今天再写新的一篇,每天做30道java的题目,感觉自己的基础知识就得好好巩固一下。

java的跨平台特性

我们编译好的文件是以.java后缀保存的,编译器会自动帮我们生成一个标准的.class字节码文件,JVM运行该文件。JVM也是一个软件,不同的系统平台JVM不同,但都可以实现标准的.class字节码文件。

数据库事务的隔离级别

4个。由低到高依次为Read uncommitted(未授权读取、读未提交)、Read committed(授权读取、读提交)、Repeatable read(可重复读取)、Serializable(序列化),这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题

                     √: 可能出现    ×: 不会出现
脏读 不可重复读 幻读
Read uncommitted
Read committed ×
Repeatable read × ×
Serializable × × ×
关于instanceof

instanceof 用来在运行时指出对象是否是特定类的一个实例,instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例

异常

checked exception:指的是编译时异常,该类异常需要本函数必须处理的,用try和catch处理,或者用throws抛出异常,然后交给调用者去处理异常。

runtime exception:指的是运行时异常,该类异常不必须本函数必须处理,当然也可以处理。
Thread.sleep()抛出的InterruptException属于checked exception;IllegalArgumentException属于Runtime exception;

java语言的下面几种数组复制方法中,哪个效率最高?

效率:System.arraycopy > clone > Arrays.copyOf > for循环
A:for循环,效率最低,随便写个程序验证一下,效率慢的不是一点…我测试的时候比clone和System.arraycopy差了100多倍

B:System.arraycopy:原型是
public static native void arraycopy(Object src, int srcPos , Object dest, int destPos, int length);

C:Arrays.copyOf底层调用了上面的System.copyOf效率比上面两个低。

D:clone()的完整定义:protected native Object clone() throws CloneNotSupportedException;

JAVA多线程的叙述正确的是

Callable类的call()方法可以返回值和抛出异常

##### 以下将打印出

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)

如果希望监听TCP端口9000,应该怎样创建socket?

new ServerSocket(9000);

抽象类(abstract class)和接口(interface)的区别
  1. 含有abstract修饰符的class即为抽象类,abstract类不能创建的实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法不必是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,所以,不能有抽象构造方法或抽象静态方法。如果的子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为abstract类型。
  2. 接口(interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
    下面比较一下两者的语法区别:
  • 抽象类可以有构造方法,接口中不能有构造方法
  • 抽象类中可以有普通成员变量,接口中没有普通成员变量
  • 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
  • 抽象类中的抽象方法的访问类型可以是public,protected和(默认类型,虽然
    eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
  • 抽象类中可以包含静态方法,接口中不能包含静态方法
  • 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
  • 一个类可以实现多个接口,但只能继承一个抽象类。

接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,

例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码.

Ant和Maven

Ant和Maven都是基于Java的构建(build)工具。理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷。Ant是软件构建工具,Maven的定位是软件项目管理和理解工具。

  1. Ant特点 ›
    没有一个约定的目录结构 ›必须明确让ant做什么,什么时候做,然后编译,打包 ›没有生命周期,必须定义目标及其实现的任务序列 ›没有集成依赖管理
  2. Maven特点
    ›拥有约定,知道你的代码在哪里,放到哪里去 ›拥有一个生命周期,例如执行 mvn install 就可以自动执行编译,测试,打包等构建过程 ›只需要定义一个pom.xml,然后把源码放到默认的目录,Maven帮你处理其他事情 ›拥有依赖管理,仓库管理
强制转换

byte和short型在计算时会自动转换为int型计算,结果也是int 型
低级向高级是隐式类型转换,高级向低级必须强制类型转换,byte=char=short<int<long<float<double
byte,short,char是同级别的,不能自动转换

finally 关键字
  1. 选项在 final 定义的方法里,不是必须要用 final 定义变量。
  2. final 定义的变量,可以在不是必须要在定义的同时完成初始化,也可以在构造方法中完成初始化。
  3. 正确,final修饰方法,不能被子类重写,但是可以被重载。
  4. final 定义变量,可以用 static

final修饰的类不能被继承, final 修饰的方法不能被重写,final修饰的属性在第一次被赋值后不可再更改值。

以下程序输出结果

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);
}
}

因为x的 修饰符为 static 所以x为类变量,即对于所有的实例来说,他们访问的x为同一个x,类变量存储在方法区,不属于每个实例的私有,

刚开始x=100

调用hs1.x++ x为101;

调用hs2.x++ x为102;

调用hs1.x++ x为103 (此时hs1指向了一个新的HasStatic实例,但是依然访问的是同一个X)

调用HasStatic.x-- x为102

所以结果为D

java 中的 wait()方法和 sleep()方法的区别
  1. 这两个方法来自不同的类分别是Thread和Object
  2. 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得敏感词线程可以使用同步控制块或者方法。
  3. wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在
    任何地方使用
    synchronized(x){
    x.notify()
    //或者wait()
    }
  4. sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常
java Object类

一共有11个: equals . getClass . hashCode . toString . notify .notifyAll .
wait . finalize . clone

一个小题

public class TestClass {
private static void testMethod(){
System.out.println(“testMethod”);
}
public static void main(String[] args) {
((TestClass)null).testMethod();
}
}

我来总结下大家的分析。
1)此处是类对方法的调用,不是对象对方法的调用。
2)方法是static静态方法,直接使用"类.方法"即可,因为静态方法使用不依赖对象是否被创建。
null可以被强制类型转换成任意类型(不是任意类型对象),于是可以通过它来执行静态方法。
3)非静态的方法用"对象.方法"的方式,必须依赖对象被创建后才能使用,若将testMethod()方法前的static去掉,则会报 空指针异常 。此处也验证了2)的观点
当然,不管是否静态方法,都是已经存在的,只是访问方式不同。

线程安全的集合类

简单记忆线程安全的集合类: 喂!SHE! 喂是指 vector,S是指 stack, H是指 hashtable,E是指:Eenumeration

java1.8实测,抽象类中的抽象方法和非抽象方法在不加修饰符的情况下,都是默认的default

webService

Webservice是跨平台,跨语言的远程调用技术

它的通信机制实质就是xml数据交换;

它采用了soap协议(简单对象协议)进行通信

super关键字

super是java提供的一个关键字,super用于限定该对象调用它从父类继承得到的Field或方法。super关键字不能出现在static修饰的方法中,因为static修饰的方法是属于类的。如果在构造器中使用super,则super用于限定该构造器初始化的是该对象从父类继承得到的field,而不是该类自己定义的field。需要注意的是,super关键字只能指代直接父类,不能指代父类的父类。(需要好好理解)

java垃圾回收机制

java提供了一个系统级的线程,即垃圾回收器线程。用来对每一个分配出去的内存空间进行跟踪。当JVM空闲时,自动回收每块可能被回收的内存,GC是完全自动的,不能被强制执行。程序员最多只能用System.gc()来建议执行垃圾回收器回收内存,但是具体的回收时间,是不可知的。
当对象的引用变量被赋值为null,可能被当成垃圾。

对于“程序可明确地标识某个局部变量的引用不再被使用”说法错误

因为,局部变量存放在栈上,栈上的垃圾回收,由finalize()来实现。

参考(https://www.importnew.com/19085.html)

重要的知识,可以自己实测

静态内部类可以访问外围类的静态数据,包括(静态)私有数据,但不能访问非静态数据;
非静态内部类可以直接访问外围类的数据,包括私有数据

final修饰变量

一、final修饰变量

  1. final可以修饰成员变量,也可以修饰局部变量、形参。final变量一旦获得初始值之后,final的变量就不能被重新赋值。

成员变量是随类初始化或对象初始化而初始化的,当执行静态初始化块时候可以对类属性进行赋初始值,当执行普通初始化块或者构造器的时候可以对实例属性赋初始值。因此成员变量的初始值可以在定义的时候赋值或者在初始化块、构造器中指定。

对于final修饰的成员变量而言,一旦有了初始值之后,就不能被重新赋值,因此不可以在普通方法中对成员变量赋值。要么在定义的时候赋值,要么在方法块和构造器中赋值。
final成员变量,必须由程序员显示初始化,系统不会对final成员进行隐式初始化。

  1. final修饰局部变量时既可以在定义时候指定默认值,也可以不指定,在后面指定,但只能一次。
  2. final修饰基本类型的时候 变量不能改变
  3. final修饰引用类型变量,final只保证这个引用的地址不变,即一直引用同一对象。但这个对象可以改变。
java 构造函数使用方法总结

使用构造器时需要记住:

  1. 构造器必须与类同名(如果一个源文件中有多个类,那么构造器必须与公共类同名)
  2. 每个类可以有一个以上的构造器
  3. 构造器可以有0个、1个或1个以上的参数
  4. 构造器没有返回值
  5. 构造器总是伴随着new操作一起调用

使用super调用父类构造器的语句必须是子类构造器的第一条语句

如果子类构造器没有显式地调用父类的构造器,则将自动调用父类的默认(没有参数)的构造器。如果父类没有不带参数的构造器,并且在子类的构造器中又没有显式地调用父类的构造器,则java编译器将报告错误

jvm中垃圾回收分为scanvenge gc和full GC,其中full GC触发的条件可能有哪些
  1. 新生代:(1)所有对象创建在新生代的Eden区,当Eden区满后触发新生代的Minor GC,将Eden区和非空闲Survivor区存活的对象复制到另外一个空闲的Survivor区中。(2)保证一个Survivor区是空的,新生代Minor GC就是在两个Survivor区之间相互复制存活对象,直到Survivor区满为止。
  2. 老年代:当Survivor区也满了之后就通过Minor GC将对象复制到老年代。老年代也满了的话,就将触发Full GC,针对整个堆(包括新生代、老年代、持久代)进行垃圾回收。
  3. 持久代:持久代如果满了,将触发Full GC。,System.gc是有可能触发full gc的
关于String,StringBuilder以及StringBuffer

A. java中的字符串存储在字符串常量区,不会改变,发生改变是会新创建一个对象
B. StringBuffer是线程安全的StringBuilder
C. StringBuilder跟StringBuffer功能相同,区别是StringBuilder不是线程安全的
D. StringBuilder和StringBuffer底层都是以字符数组存放的,可以修改内容

JDK提供的用于并发编程的同步器有哪些

A. Java 并发库 的Semaphore 可以很轻松完成信号量控制,Semaphore可以控制某个资源可被同时访问的个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。
B. CyclicBarrier 主要的方法就是一个:await()。await() 方法没被调用一次,计数便会减少1,并阻塞住当前线程。当计数减至0时,阻塞解除,所有在此 CyclicBarrier 上面阻塞的线程开始运行。
C. 直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。

jre 判断程序是否执行结束的标准是()

所有的前台线程执行完毕

##### 经过强制类型转换以后,变量a, b的值分别为( )short a = 128; byte b = (byte) a;
128 -128

解析:byte在内存中占一个字节,范围是 -128到127之间。
将128强制类型转换为byte型,就超出了byte型的范围,
128的二进制存储是 1000 0000 转换为byte型后,最高位是符号位,值是-128

JAVA异常类

参考(https://www.cnblogs.com/sargeles/p/6691383.html)

有关JVM内存

运行时数据区包括:虚拟机栈区,堆区,方法区,本地方法栈,程序计数器
虚拟机栈区 :也就是我们常说的栈区,线程私有,存放基本类型,对象的引用和 returnAddress ,在编译期间完成分配。
堆区 , JAVA 堆,也称 GC 堆,所有线程共享,存放对象的实例和数组, JAVA 堆是垃圾收集器管理的主要区域。
方法区 :所有线程共享,存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。这个区域的内存回收目标主要是针对常量池的对象的回收和对类型的卸载。
程序计数器 :线程私有,每个线程都有自己独立的程序计数器,用来指示下一条指令的地址。

hashMap跟hashTable的区别

①继承不同。

public class Hashtable extends Dictionary implements Map public class HashMap extends AbstractMap implements Map


Hashtable 中的方法是同步的,而HashMap中的方法在缺省情况下是非同步的。在多线程并发的环境下,可以直接使用Hashtable,但是要使用HashMap的话就要自己增加同步处理了。

Hashtable中,key和value都不允许出现null值。
在HashMap中,null可以作为键,这样的键只有一个;可以有一个或多个键所对应的值为null。当get()方法返回null值时,即可以表示 HashMap中没有该键,也可以表示该键所对应的值为null。因此,在HashMap中不能由get()方法来判断HashMap中是否存在某个键, 而应该用containsKey()方法来判断。
④两个遍历方式的内部实现上不同。
Hashtable、HashMap都使用了 Iterator。而由于历史原因,Hashtable还使用了Enumeration的方式 。

哈希值的使用不同,HashTable直接使用对象的hashCode。而HashMap重新计算hash值。

Hashtable和HashMap它们两个内部实现方式的数组的初始大小和扩容的方式。HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。

下列说法

A. ConcurrentHashMap实际上时 HashTable的升级版,使用segment来分段和管理锁,并不是synchronized;
B. HashMap实现的接口有:Serializable, Cloneable, Map<K,V> ,没有实现Cllectio
C. Arrays.asList()方法返回的列表是Arrays.ArrayList类型的,并不是java.util.ArrayList;
D. SimpleDateFormat是线程不安全的

对于以下程序 输出

public class StringDemo{
private static final String MESSAGE=“taobao”;
public static void main(String [] args) {
String a =“tao”+“bao”;
String b=“tao”;
String c=“bao”;
System.out.println(a==MESSAGE);
System.out.println((b+c)==MESSAGE);
}
}
true false

要注意两个问题:
1,字符串在java中存储在字符串常量区中
2,==判断的是对象引用是否是同一个引用,判断字符串相等要用equals方法
首先判断a==MESSAGE 同一份字符串常量在内存中只有一份,因此是同一地址,返回true
再次比较(b+c)==MESSAGE 这相当于 new String(b+c)==MESSAGE 这里new了一个String对象,所以返回false

Tags: Java
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏

扫描二维码,分享此文章