每当产生异常后,如果没有程序进行相应的处理,则程序将出现中断现象。那么,此时实际上一旦产生异常之后,JVM会抛出一个异常类的实例化对象,如果此时使用try语句进行捕获的话,则可以进行异常处理。如果没有的话,则交给JVM进行处理,当try语句捕获到异常之后,会与catch中的异常类型进行匹配,如果匹配成功,则使用此catch语句进行处理。
应用:简单的引用,就是在所有有throws关键字的地方加入try...catch,如:
// 定义一个方法 public void method() throws Exception; // 调用方法(method),然后使用try catch进行捕获 try { method(); } catch(IOException e) { ... } catch(Exception e) { ... }
如果按照一个标准做法的话,try、catch、finally、throw、throws关键字应该一起使用。
垃圾回收是将无用的对象空间进行释放,两种回收:
自动回收(JVM根据垃圾回收算法进行自动回收)
手工调用System.gc()方法,实际上调用System.gc()就相当于调用了Runtime.getRuntime().gc()方法。
Error 是 Throwable 的子类,用于合理的指示应用程序不应该试图捕获的严重问题。大多数这样的错误都是有异常条件。虽然 ThreadDeath 错误是一个“正规”的条件,但它也是 Error 的子类,因为大多数应用程序都不应该试图捕获它。
Exception是可以由程序进行处理的,使用try...catch语句进行处理。
总结,Error错误是严重的不可逆转的,不推荐进行捕获;Exception错误是可逆转的,大多数情况下用户是希望进行捕获的。
final是定义常量、方法、类的、声明的方法不能被覆写、声明的类不能被继承。如下:
public final class Test { public static final String FIELD = ""; public final void showMsg() { ... } }
fianlly是异常的统一出口,配合try...catch使用。
public class Test { public static void main(String[] args) { try { // ... } catch(Exception e) { // ... } finally { // ... } // 或者 try { // ... } finally { // ... } } }
finalize是垃圾回收前的收尾工作,是Object类中定义的。如下:
public class Object { ... protected void finalize() throws Throwable { } ... }
允许继承和实现,因为匿名内部类就是在抽象类和接口的基础之上发展起来的。
使用static声明的内部类就是外部类,可以通过外部类直接访问。如下:
package com.huangx.innerClass.statics; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 测试静态内部类的创建和使用 * * @author Administrator * @date 2018-02-22 14:17 */ public class StaticInnerClass1 { private static final Logger log = LoggerFactory.getLogger(StaticInnerClass1.class); public static void main(String[] args) { MyStaticInnerClass t = new MyStaticInnerClass(); t.show(); } static class MyStaticInnerClass { public MyStaticInnerClass() { log.debug("MyStaticInnerClass()"); } public void show() { log.debug("MyStaticInnerClass >> show()"); } } }
普通的内部类是不能够直接被外部所访问的,需要通过外部类实例再找到内部类的实例。如下:
package com.huangx.innerClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 创建内部类,且使用内部类语法 * * @author Administrator * @date 2017-10-17 */ public class InnerClass1 { private static final Logger log = LoggerFactory.getLogger(InnerClass1.class); public static void main(String[] args) { // 创建实例 InnerClass1 t = new InnerClass1(); // 创建内部类实例 Inner01 inner01 = t.new Inner01("ZhangSan", 28); inner01.show(); } class Inner01 { private String name; private int age; public Inner01(String name, int age) { this.name = name; this.age = age; log.debug("Inner01({}, {});", name, age); } public void show() { log.debug("show() :: name={}, age={}", this.name, this.age); } } }
HashMap
|-JDK1.2之后推出,是新类
|-采用异步处理方式,性能较高,但是属于非线程安全
|-允许设置null
HashTable
|-JDK1.0时推出,是旧类
|-采用同步处理方式,性能较低,但是属于线程安全
|-不允许设置null,否则将出现NullPointerException
JDK1.4之后增加的新关键字assert,表示断言,即程序执行到某个地方之后值肯定是预计好的。
一般在开发中很少使用assert。如果你想要使用断言,必须使用-ea参数。如下:
package com.huangx.asserts; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class AssertTest1 { private static final Logger log = LoggerFactory.getLogger(AssertTest1.class); public static void main(String[] args) { int a = 10; assert a > 0; log.debug("a = {}", a); int b = -1; assert b > 0 : "b Must be greater than 0"; log.debug("b = {}", b); } }
必须使用-ea参数开启assert功能:
java -ea AssertTest1
GC即垃圾收集。使用GC可以进行垃圾空间的释放JVM内存资源。
创建了几个String Object?产生了两个实例对象,一个是匿名对象"xyz",另一个是通过关键字new实例化的。
sleep()是Thread中定义的方法,表示线程的休眠,会自动唤醒。
wait()是Object中定义的方法,需要手动的调用notify()或notifyAll()方法。
goto属于保留的关键字,Java中存在goto关键字,只是无法使用。
数组中存在length属性,String中存在length()方法。
重载(Overload):
|- 在一个定义的若干方法
|-所有的方法名称相同,但是参数的类型或个数不同
覆写(Override):
|-在继承的关系中
|-子类定义与父类同名的方法,参数类型个数最好完全相同,注意访问权限不能更加严格
重载的时候不是依靠返回值类型区分的,而是靠参数。
hashCode()和equals()方法。使用的是equals()方法,“==”属于地址值比较,而equals()属于内容比较。如下:
public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Set)) return false; Collection c = (Collection) o; if (c.size() != size()) return false; try { return containsAll(c); } catch (ClassCastException unused) { return false; } catch (NullPointerException unused) { return false; } }
上面是HashSet中对equals方法的实现(在AbstractSet类中进行实现)。
NumberFormatException(数字格式化异常)
ArrayOutIndexofBoundException(数组下标溢出)
NullPointerException(空指针异常)
ClassCastException(类转换异常)
抽象类:
|-有抽象方法和常量、变量、全局变量、构造方法、普通方法组成
|-使用abstract声明
|-子类要通过extends继承抽象类,子类如果不是抽象类,则必须覆写抽象类中的所有抽象方法
|-存在单继承局限,一个子类只能继承一个抽象类
|-抽象类可以实现若干个接口
接口:
|-全部由抽象方法和全局常量组成
|-使用interface声明
|-子类通过implements实现接口,子类如果不是抽象类,则必须覆写接口中的所有抽象方法
|-不存在单继承局限,一个类可以同时实现多个接口
|-接口不能继承一个抽象类,但是允许继承多个接口
使用start()方法,因为要通知JVM进行CPU资源分配。如果直接调用run()方法,则和调用普通的方法类似。
public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException(); /** * Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ group.add(this); boolean started = false; try { start0(); started = true; } finally { try { if (!started) { group.threadStartFailed(this); } } catch (Throwable ignore) { /** * do nothing. If start0 threw a Throwable then * it will be passed up the call stack */ } } } private native void start0();
从上面代码可以看出,start方法内部是调用本地start0方法来启动线程。
try{}里有一个return语句,那么紧跟在try后面的fianlly{}里面的代码会不会执行,什么时候执行,在return前还是在之后呢?
会执行,在return之前执行。测试代码如下:
private String test1M() { try { log.debug("## try"); // 1 return "## return"; // 3 } finally { log.debug("## finally"); // 2 } } @Test public void test1() { log.debug( test1M() ); } /* 结果: 13:58:47 DEBUG [com.huangx.test.Test01] - ## try 13:58:47 DEBUG [com.huangx.test.Test01] - ## finally 13:58:47 DEBUG [com.huangx.test.Test01] - ## return */
但是如果使用类System.exit(0)将不会执行。测试代码如下:
private String test2M() { try { log.debug("## try"); // 1 System.exit(0); return "## return"; } finally { log.debug("## finally"); } } @Test public void test2() { log.debug(test2M()); } /* 结果: 13:59:22 DEBUG [com.huangx.test.Test01] - ## try */
单例模式分为饿汉式和懒汉式两种实现方式,下面将使用饿汉式实现,代码如下:
package com.test; public class Singleton{ private static final Singleton single = new Singleton(); private Singleton(){} public static getInstance(){ return single; } }
假设数字中间使用空格进行分隔。
package com.test; import java.io.*; import java.util.*; public class Demo{ public static void main(String[] args)thorws Exception{ BufferedReader buf = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一串数字,中间使用空格分隔:"); String str = buf.readLine(); Set<Integer> set = new TreeSet<Integer>(); String[] s = str.split(" ");//进行拆分 for(String x:s){ set.add(Integer.parseInt(x));//加入数据 } System.out.println("排序后的结果:"); for(Iterator it = set.iterator(); it.hasNext();){ System.out.println(it.next() + "、 "); } } }
以上的操作中,因为所有数据都已经假设是正确的数字,但是实际中有可能是字符串。
第一种方法:允许有字符串,但是将所有的字符串忽略。
第二种方法:不允许有字符串,如果出现字符串,则程序不能继续向下运行。
改善程序:
package com.test; import java.io.*; import java.util.*; public class Demo{ public static void main(String[] args)thorws Exception{ BufferedReader buf = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一串数字,中间使用空格分隔:"); String str = buf.readLine(); Set<Integer> set = new TreeSet<Integer>(); System.out.println("(" + str.replaceAll("\\D+", " ") + ")"); String[] s = str.repaceAll("\\D+", " ").trim().split(" +");//进行拆分 for(String x:s){ set.add(Integer.parseInt(x));//加入数据 } System.out.println("排序后的结果:"); for(Iterator it = set.iterator(); it.hasNext();){ System.out.println(it.next() + "、 "); } } }
此时我们需要是File类的listFiles和递归配合使用。如下图:
package com.test; import java.io.*; public class ListFiles{ public static void main(String[] args){ File file = new File("D:" + File.separator + "doc"); fun(file); } // 列出文件列表 public static void fun(File file){ if(file.isDirectory()){ File f[] = file.listFiles(); if(f != null){ for(int i=0; i<f.length; i++){ fun(f[i]); // 递归入口 } } }else{ System.out.println(file); // 递归出口 } } }
可以存放。因为Java使用的是unicode编码。如下:
@Test public void test1() { char[] chars = {'<', '中', '国', '>'}; log.debug("{}", Arrays.toString(chars)); }
多线程有两种实现方法:
继承Thread类
实现Runnable接口
Thread类是Runnable的子类,使用Runnable接口可以实现资源共享的目的。所有的线程操作都必须由Thread类的start()方法启动。实现两种同步的方法:
同步代码块
public void test() { synchronized(this) { ... } }
同步方法
public synchronized void test() { ... }
不正确,因为默认情况下3.4是double类型。
String不可修改(不变模式),StringBuffer可以修改。因为StringBuffer是通过char数组进行维护的,因此是可变的。如下:
abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */ char[] value; ... }
如上,StringBuffer的大部分功能是在AbstractStringBuilder类进行实现,其中通过char[]数组进行完成。
Class.forName方法用于向JVM中加载给定的类(通过反射去使用类),例如:加载JDBC驱动,如下:
public void hello() { try { Class.forName("com.mysql.jdbc.Driver"); // ... } catch(Exception e) { e.printStackTrace(); } finally { // 释放资源 } }
使用Class.forName方法可以通过程序动态的加载给定的类。
int是基本数据类型、Integer是包装类。在JDK1.5之后,可以实现自动装箱和拆箱的操作。如下:
/** * 测试自动装箱和拆箱功能 */ @Test public void autoCase() { // 拆箱 int a = Integer.valueOf(100); log.debug("a = {}", a); // 装箱 Integer b = 200; log.debug("b = {}", b); }
注意:自动装箱和拆箱是JDK1.5+版本添加的,对编写代码更便捷。
该考题主要考察对Java位移操作。本题中,2乘以几是最有效的,无疑是通过位移来进行操作。使用:2<<3(即2^3,2的3次方),更多关于位移操作见下面。
Java中的移位运算符有三种:
<<: 左移
>>: 右移
>>>: 无符号右移
使用方法
左移就是将左边的操作数在内存中的二进制数据左移指定的位数,左边移空的部分补零,右移:如果最高位是0,空位就填0,如果最高位是1,空位就填1。无符号右移无论最高位是什么,空位都补零。
数据在内存中以补码的形式存储
左移和右移的数学意义
对于左移,对于整型a, a<<n=a*2^n(前提是结果在整型的范围之内),对于右移正的整型a, a>>n=a/2^n,对于负的整型a,a>>n=-(|a|/2^n+1)。
为什么对于右移,正数和负数的结果不一样呢?我们可以看一个例子:
public class Test { public static void main(String[] args) { int a = -123; System.out.println("原二进制位:" + Integer.toBinaryString(a)); int b = a >> 2; System.out.println("右移两位结果为:" + b); System.out.println("右移后二进制位:" + Integer.toBinaryString(b)); int c = 123; System.out.println("原二进制位:" + Integer.toBinaryString(c)); int d = c >> 2; System.out.println("右移后的结果为:" + d); System.out.println("右移后二进制位:" + Integer.toBinaryString(d)); } }
集合框架最大的接口:Collection(集合,分为:List列表和Set集合)、Map(映射)、Iteraotr(迭代器)、Enumeration(迭代器)。如:
+ Collection:存放单值 + List:允许有重复内容、有顺序 + ArrayList:异步处理,新操作类,非线程安全 + Vector:同步处理,旧的操作类,线程安全,支持Enumeration输出 + Set:不允许有重复内容,靠hashCode()和equals()方法进行重复验证,无顺序 + HashSet:无须存放 + TreeSet:有序存放,按Comparable排序 + Map:存放键值对 + HashMap:新的类,异步处理,非线程安全,允许有null + HashTable:旧的类,同步处理,非线程安全,不允许有null + Properties:属性操作类 + TreeMap:有序排列,按key排序,根据Comparable指定排序规则 + Iterator:迭代输出,依靠Collection接口中的iterator()方法。是新的输出标准 + Enumeration:是旧的输出类
上面列举了集合框架的大部分API,更多的API请查阅JDK API文档。
String类不允许进行继承,因为Sting类使用了final关键字进行声明(final声明的类不允许继承,final声明的方法不允许重写)。部分源码如下:
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; ... }