List a = new ArrayList();
a.add(1);
a.add(2);
a.add(3);
a.remove(1);
public E remove(int index); //执行删除指定位置的元素的功能
public boolean remove(Object o) //执行删除指定元素的功能
如果传入参数是int(自动装箱为Integer)时,调用哪个方法?
应该调用删除指定位置元素的方法,因为重载方法会优先调用参数类型最符合类型的(相等,或最小包含的)。
// <> 左有 左无 左有值 右有 右无 右有值 共9种
// 其中<>左有是非法的 9-3 =6种
// 剩下6种都是合法的
// 其中<>左无的list没有特定的泛型,add()任何对象都可以
// 但是<>左有值的list只能添加泛型类型,否则会编译错误
//List list = new ArrayList(); <>都没有
//List list = new ArrayList<>(); <>右边有,左边没有
List list = new ArrayList<Student145>();
//List list = new ArrayList(); <>左边有值,右边没有
//List list = new ArrayList<>();
//List list = new ArrayList();
接口:Map接口,Map子接口Entry、SortedMap、NavigableMap
子类:HashMap、TreeMap、HashTable、LinkedHashMap
接口:Collection (继承自Iterable接口)、Iterator接口(子接口ListIterator) 子接口有Set(子接口SortedSet、NavigableSet)、List、Deque、Queue
子类:Vector、ArrayList、LinkedList(List子类)、ArrayDeque、PriorityQueue、HashSet、LinkedHashSet、TreeSet
虽然使用HashMap会浪费空间,但是HashMap底层是位桶数组+链表+红黑树实现,比LinkedList链表实现查询会快很多。
集合子类的底层实现:
泛型与强制类型转换的关系是针对于:
jdk5之前没有泛型,声明一个List时,使用
List list = new ArrayList();
这样的形式,加入元素没有类型限制,但是对于取出元素,就要对每个元素进行强制类型转换,很容易出现ClassCastException运行时异常。
提出泛型后,限制了集合的类型,要声明一个泛型List:
List<String> list = new ArrayList<>();
泛型List对放入的集合元素有类型限制,但是取出元素,不需要再进行强制类型转换。
//假设文件 c:/a.txt 的内容为 abc
try {
File f = new File("c:/a.txt");
System.out.print(f.length());
OutputStream out = new FileOutputStream(f);
System.out.print(f.length());
out.write(97);
System.out.print(f.length());
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//执行后,控制台输出为?
File类中的length():
如果文件不存在/文件是目录且为空/文件为空,都返回0。
返回的是字节数,一个英文字母/数字是1字节,一个汉字是3字节(utf-8编码,如果是GB2312/ANSI编码是2字节,UTF16是4字节,带有BOM的UTF-8是6字节)
以下哪个流可以将数据写入到内存中?ByteArrayOutputStream
bais/baos不是将数据写入硬盘,而是写入内存。内存的数据在断电后不会被保存。
try {
FileWriter w = new FileWriter("c:/a.txt");
w.write("abc");
w.append("world");
w.write("kof98");
w.close();
} catch (IOException e) {
e.printStackTrace();
}
FileWriter中write()和append()区别:
@Override
public Writer append(CharSequence csq) throws IOException {
if (csq instanceof CharBuffer) {
se.write((CharBuffer) csq);
} else {
se.write(String.valueOf(csq));
}
return this;
}
public void write(int c) throws IOException {
se.write(c);
}
静态导入是jdk5的新特性,作用是导入静态的成员,比如类中的静态方法或者静态变量。
语法是import static 包名.类名.静态成员名,也可以是import static 包名.类名.*导入类中所有的静态成员。
静态导入的作用是导入后可以直接使用静态方法名和静态变量名,比如
import static java.lang.System.*;
out.println("");
setIn(new FileInputStream(new File("")));
public static final PrintStream out = null;
public static void setIn(InputStream in) {
checkIO();
setIn0(in);
}
可以直接使用System类中的静态对象out,不需要带类名。
但是静态导入也可能和类中同名的变量/方法冲突。
[单选]
以下代码
import java.lang.reflect.Method;
public class Test {
private String name;
private void eat(int num,String food) {
System.out.print("吃"+num+"个"+food);
}
public static void main(String[] args) {
try {
Class c = Class.forName("Test");
Test t1 = (Test)c.newInstance();
Method m = c.getDeclaredMethod("eat", int.class,String.class);
m.invoke(t1, 3,"面包");
} catch (Exception e) {
e.printStackTrace();
}
}
}
执行后,控制台输出为?
Method类中的invoke()方法:
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException{...}
调用的Method的对象是通过反射获取的方法对象,第一个参数不可以省略,代表通过反射获取的实例对象,后面的参数可以省略,代表实参列表。
public class Test {
private String name;
public int age;
public Test(String name, int age) {
this.name = name;
this.age = age;
}
private Test(String name) {
this.name = name;
}
Test(int age) {
this.age = age;
}
public static void main(String[] args) {
try {
Class c = Class.forName("Test");
Test t = (Test)c.newInstance();
System.out.println(t.name);
} catch (Exception e) {
e.printStackTrace();
}
}
}
反射中创建新对象的方法:
Class.newInstance() 只能够调用无参的构造函数,即默认的构造函数;
Constructor.newInstance() 可以根据传入的参数,调用任意构造构造函数。
当类中存在其他有参构造函数,且不存在无参构造函数的时候,使用无参构造方法会抛出异常InstantiationException,是一个运行时异常。
如果forName()的类名和实际类名不符,会抛出ClassNotFoundException异常,是非检查时异常,也不是运行时异常。
如果存在无参构造方法,但是权限访问不到,Class.newInstance()方法会抛出IllegalAccessException异常,也是一个运行时异常。
Constructor的成员方法也会抛出这两个异常,还会抛出非法参数异常,以及InvocationTargetException,是当被调用的方法的内部抛出了异常而没有被捕获时,将此异常会将其接收。
线程进入等待状态后,对该锁发出notify()方法后,线程会进入就绪状态而不是运行状态。
线程的优先级的作用:
优先级高的线程获得更多的时间片,优先级较低的线程获得较少的时间片。所以与线程的执行顺序没有关系,但是相同的任务量,优先级高的线程在较少的轮转次数(或者时间片没用完)就会执行完,而优先级低的线程会在后面执行完。
sleep()让线程进入阻塞状态
yield()让线程进入就绪状态。
setDaemon() 的作用是将指定的线程设置成后台线程,说法正确。后台进程等价于守护线程。
对某个对象调用wait()方法不一定会让当前线程等待,因为它可能属于其他线程。
多线程:
因为共享进程数据,数据共享简单,但也是因为这个原因导致同步复杂
占用内存少,切换简单,CPU利用率高
创建销毁、切换简单,速度很快
改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
线程的调度不需要内核直接参与,控制简单。CPU调度还是以进程为单位
try-catch-finally可能的执行流程:
(1)try、catch、finally都没有return语句或system.exit(0):执行完块往下接着运行
(2)try/catch有return;,finally没return:有无异常进不同的块,如果该块中有return,会执行完finally再回来return;
(3)try/catch有return;,finally也有return:最终执行finally中的return;
(4)try/catch中有system.exit(0):遇到system.exit(0)直接退出程序
(5)多个catch块,父异常在子异常块前面:编译错误
(6)多个catch块,子异常在父异常块前面:该进哪个进哪个
Comparable:
@Override
public int compareTo(Student145 s) {
//comparable需要一个参数,当this的数-参数的数>0,或者this的数大于参数的数返回1时,是升序排序
//否则是降序排序
//return this.getAge()>s.getAge()?1:-1;//按照升序排序
//return s.getAge()>this.getAge()?1:-1;//按照降序排序
//return this.getAge()-s.getAge();//按照升序排序
//return s.getAge()-this.getAge();//按照降序排序
return 0;
}
Comparator:
Comparator<Student145> comparator = new Comparator<Student145>() {
@Override
//comparator需要两个参数,当返回第一个数-第二个数,或者第一个数大于第二个数返回1时,是升序排序。
//否则是降序排序。
public int compare(Student145 s1, Student145 s2) {
//return s1.getAge()>s2.getAge()?1:-1;//按年龄升序排序
//return s2.getAge()>s1.getAge()?1:-1;//按年龄降序排序
//return s1.getAge()-s2.getAge();//按年龄升序排序
//return s2.getAge()-s1.getAge();//按年龄降序排序
return 0;
}
};
stream.max((Object a,Object b)->{return (Integer)a-(Integer)b;}).get())
属于外部比较器,第一个减第二个的形式,所以是升序排序。
max(),get()实际上是取最后一个(升序排序最大值,降序排序最小值)。
原理是,max()会留下两个数比较,比较器返回正数的那个数字(对象),这样留下的永远是最大(1)的。
List<Integer> list = new ArrayList<>();
list.add(10);
list.add(11);
list.add(12);
list.add(5);
list.add(6);
Stream<Integer> s = list.stream();
//猜想 正数就留下第一个, 负数就留下第二个
//比较过程是 10&11 11&12 12&5 12&6 留下12
System.out.println( s.max((Integer a,Integer b)->(a-b)).get());//等价于Integer::compareTo
s = list.stream();
//比较过程是 10&11 10&12 10&5 5&6 留下5
System.out.println( s.max((Integer a,Integer b)->(b-a)).get());
s = list.stream();
//比较过程是 10&11 10&12 10&5 10&6 留下10
System.out.println( s.max(Integer::max).get());
List<Integer> list2 = new ArrayList<>();
list2.add(-1);
list2.add(-2);
list2.add(-3);
list2.add(-4);
list2.add(-5);
list2.add(-6);
s = list2.stream();
//比较过程是 -1&-2 -2&-3 -3&-4 -4&-5 -5&-6 最后留下-6
System.out.println( s.max(Integer::max).get());
\w 匹配字母或数字或下划线或汉字 等价于 ‘[^A-Za-z0-9_]’。
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束。\b匹配这样的结构:\b两边,一边是单词的字母\w,一边是隐式占位符(?)。比如a\bnice是非法的,\bnice\b会匹配到n开头e结尾的,er\b可以匹配到r结尾的单词。
{n}表示匹配的长度
URL 类所指向的资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用,例如对数据库或搜索引擎的查询
class InetAddress implements java.io.Serializable
InetAddress不是抽象类,但是无参构造方法是default修饰的。
InetAddress() {
holder = new InetAddressHolder();
}
阻塞是指程序会一直等待该方法完成期间不做其他事情。
ServerSocket的accept方法就是一直等待客户端连接。这里的阻塞是指调用结果返回之前,当前线程会被挂起,直到得到结果之后才会返回。
RetentionPolicy.SOURCE表示保留到.java源文件期间,编译不再保留注释。
javadoc会忽略注解,但是使用@Documented修饰的注解不会被忽略掉。
使用@Documented修饰的注解中,只有成员方法没有成员变量。
@Override的作用是重写不是重载。重载不需要注解。
interface M{
public default void a() {
System.out.println("1");
}
}
interface N{
public default void a() {
System.out.println("2");
}
}
public class A implements M,N {
public static void main(String[] args) {
new A().a();
}
}
执行后,控制台输出为?编译报错还是执行报错
实现多个接口,接口中有同名的默认方法,如果不在实现类/子接口中重写,会报编译错误。
重复注解是jdk8的一个新特性,jdk8以前不可以使用多个相同注解修饰同一对象。
重复注解定义:
import java.lang.annotation.Repeatable;
//包装类 成员变量是注解数组 方法名和注解成员方法同名
@interface Authorities {
Authority[] value();
}
//需要用@Repeatable(包装类.class)修饰
@Repeatable(Authorities.class)
public @interface Authority {
String value();//成员方法
}
//使用多个相同注解修饰
@Authority(value = "Admin")
@Authority(value = "Manager")
interface AuthorityInterface {
}
生成Stream的方法:
Collection.stream();
Collection.parallelStream();
Stream类的中间方法,返回值也是Stream
Stream.empty();返回空stream
Stream.of(T t)、Stream.ofNullable(T t)、Stream.of(T… values):返回单个元素的stream
Stream.build();
Arrays.stream(T[] array)、Arrays.stream(T[] array,int a,int b);
Stream.max()方法返回的是一个Optional对象,也就是可能为空的对象。
Stream.map()的参数是一个Function函数式接口,也就是传入一个对象,返回与他有一定联系的另一个类型的值。