面试要点:

JAVA基础:

内存管理:

Java 的内存区域:

堆:对象(成员变量)

栈:局部变量(形参)

方法区:类的所有信息

内存溢出:

  剩余内存不足以分配给请求的资源:OutOfMemoryError

内存泄漏: 分配出去的内存回收不回来

GC:是一个守护(后台)线程 System.gc() finalize():任何一个对象所属的类中都有这个方法,作用:GC回收对象前,做最后的资源释放

public class Student {
private int id;

public Student() {
    super();
    // TODO Auto-generated constructor stub
}

public Student(int id) {
    super();
    this.id = id;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

@Override
public String toString() {
    return "Student [id=" + id + "]";
}

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Student other = (Student) obj;
    if (id != other.id)
        return false;
    return true;
}

@Override
protected void finalize() throws Throwable {
    System.out.println("最后的资源释放");
}

}

public class FinalizeDemo {
public static void main(String[] args) {
    //创建一个Student对象
    Student student = new Student(1);
    //一系列对此对象的引用操作
    //对象使用结束
    student = null;
    //让GC尽快回收此垃圾
    System.gc();
}

}

案例:

public class Demo01 {
public static void main(String[] args) {
    int i = 3;
    String str = "gbk";
    char[] chs = {'a','b','c'};
    Demo01 demo01 = new Demo01();
    demo01.change(i, chs);
    //System.out.println(str);  //gbk  
    System.out.println(i)  //3
    System.out.println(chs);  //k  b  c
}

public void change(int i,char[] chs){
    //str1 = "abk";
    i = 12;
    chs[0] = 'k';
}
}

问题:Java中参数的传递是值传递还是引用传递

Java中的参数传递只有值传递

OOP

特点:封装,继承,多态

各自特点注意点:

1.封装中的成员变量的数据类型一定是引用类型

2.继承注意点:

子类继承父类,不继承的成员有哪些?

私有的,构造方法,static成员

注意点:对象的初始化顺序

案例:

public class Super {
    int a = 6;
    public Super(){
        test();
    }
    public void test(){
        System.out.println(a);
    }
}

public class Sub extends Super {
    int a = 8;

    public Sub(){
        test();
    }
    public void test(){
        System.out.println(a);
    }
}
public static void main(String[] args) {
    new Sub();
}

打印结果: 0   8

重写:不论是通过父类的引用还是子类的引用指向子类对象,调用到的都是重写后的方法

Super su = new Sub();

Sub sub = new Sub();

su.test()

sub.test()

重写遵循运行期绑定原则

案例2:

public class ExtendsConstrutorsDemo02 {
public static void main(String[] args) {
    new B();
}
}

class A{
    A(){
        System.out.println("A构造方法");
    }
}
class C{
    C(){
        System.out.println("C构造方法");
    }
}
class B extends A{
    private  C c = new C();
    B(){
        System.out.println("B构造方法");
    }
}

打印结果: A C B

考点:构造方法中的执行顺序:super()->初始化成员变量->执行其余代码

多态:

对象造型:

向上造型:

父类 引用 = new 子类对象

强制造型:

1.向下造型:

如何正确的向下造型

造型成的类型必须和运行期对象的类型是一致的。

前提:

class Teacher extends Person

class Student extends Person

正确的向下造型:

Person per = new Student();

Student stu = (Student)per;


不正确的向下造型

情况1:

Person per = new Student();

Teacher te = (Teacher)per;

情况2:

Person per = new Person();

Student stu = (Student)per;

2.强制造型2:

public class ClassCastDemo02 {
public static void main(String[] args) {
    //向上造型
    SuperCls cls = new SubCls();
    //想访问到子类中的test方法
    //方式一:向下造型
//  SubCls cls2 = (SubCls)cls;
//  cls2.test();

    //方式二:强制造型成接口类型
//  T1 t = (T1)cls;
//  t.test();

    //错误的强制造型
    SuperCls cls2 = new SubCls1();
    T1 t = (T1)cls2;
}
}

interface T1{
    void test();
}

class SuperCls{
    public void demo(){}
}

class SubCls1 extends SuperCls{

    @Override
    public void demo() {
    }

}

class SubCls extends SuperCls implements    T1{
        @Override
        public void test() {}

        @Override
        public void demo() {}

        public void myMethod(){}

    }

可以通过强制造型,将super引用转型成T1类型

    Super-->T1
    T1 t = (T1)super;
    t.test()
强制造型成功的条件:

造型成的类型必须和运行期的对象类型有关系。

instanceof:用于在强制转型时进行判断

用法:引用 instanceof 数据类型 - boolean

API部分:

API部分知识点:

常用类:

1.Object:

方法:

toString() 类型@散列码值(十六进制)

hashCode() int(十进制)

equals():用于比较两个对象是否相等,作用等同于==,通常建议重写,使其更具有实际意义,JAVAAPI中的很多类都重写了此方法

2.基本数据类型的包装类Wrapper

自动装箱,自动拆箱

3.String:

1.String类对象一旦创建,值不可以改变

2.String本质是字符数组 : toCharArray():char[]

3.String对象的创建:2种方法

方式一:new String(String str)  :保存与堆中
方式二:"" :保存在常量池

常见面试题:

1.String str = new String("abc")问:创建了几个String对象:  2个

2.String s1 = "a",s2 = "b",s3 = "ab",s4 = "a"+"b", s5 = s1+s2;

问题:s3==s4  true      s3==s5  false

StringBuilder:用于字符串操作

原理:底层是动态数组,可以实现在同一个对象基础上进行字符串的修改拼接操作

拼接,修改,删除

构造方法:new StringBuilder(String str)

注意点: String的拼接可以使用 String+String,会产生新的String对象,这种方式的拼接底层其实采用的就是StringBuilder

String s1 = "a",s2 = "b"  
String s3 = s1+s2;  //新创建String对象

其底层实现是:
    StringBuilder builder = new StringBuilder(s1);

    builder.append(s2); 

    String s3 = builder.toString();

StringBuffer

和StrinbBuilderAPI是一样的。区别在于StringBuilder是非线程安全的,效率更高,StringBuffer是线程安全的,效率稍低

日期操作类

1.Date:

Date date = new Date();

方法:

getTime():long

setTime(long)

2.SimpleDateFormat

//用户输入的字符串的日期表示 2018-04-26
//要求java程序将此日期用户程序中使用 String->Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

//String -->Date
Date date = sdf.parse(str)

Calendar:抽象类

方法:

对象的创建:2种方法

1.创建其子类对象

2.调用其static方法getInstance():Calendar-常用的

用于获取或设置日历的字段值

1.get系列方法: get(int Field):int 用于获取指定日历的日历字段值 Field:YEAR MONTH DATE DAYOFWEEK

getTime():Date

getTimeInMills():long

2.set系列

set(int Field,int value)
setTime(Date)

3.add(int field,int amount)

正则表达式:

字符集

单个字符表示的字符集

[abc] [a-zA-Z0-9]

预定义字符:

. 任意字符

\d 所有数字

\w [a-zA-Z0-9_]

\s 所有的空白字符 \r \n \t

\D 非数字

\W 与\w相反

\S 非空白字符

使用预定义字符集需要转义 \

数量词字符:

?  0/1   
+  >=1  
*  任意次
{m} 前一个字符正好匹配m次
{m,} 前一个字符匹配>=m次
{m,n} 前一个字符匹配m<=x<=n

分组():将多个部分看成一个整体,通常是和|配合使用的

案例:匹配用户输入的手机号 +86|0086 手机号

边界匹配:^开始 $结尾

在Java中写正则表达式可以省略边界匹配符,前提:调用matches方法。原因:matches方法自带边界匹配功能。

String类中的正则API:

matches(String regex):boolean

split(String regex):String[]

repalceAll(String regex,String replacement)

案例:用户输入字符串的日期格式 : yyyy-MM-dd,要求用户输入的日期必须符合现实,月份1-12,日期取决于月份 -- 分组

思路:
大月:135781012 - 31  
小月:46911 - 30
二月:2  - 28

String regex = "[1-9]\\d{3}-(
((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))
|((0[469]|11)-(0[1-9]|[12][0-9]|30))
|(02-(0[1-9]|1[0-9]|2[0-8])))"

规律:()通常都是和|配合使用的,|的外面都会有()

集合:

Collection:接口

方法

List子接口:可重复集

特点:线性表 ,有索引操作的

1.方法

2.List和Array的转换

List集合可以转换成Array

toArray():Object[] 
toArray(T[] a):T[]:常用的

Array转换成List

String[] ary = {...}
ary -- >List
Arrays.asList():List<String>

Arrays.asList(T...a):List<T>

T...a:可变参数

可变参数:

1.可变参数的实质:可变数组

2.可变参数的访问和数组的访问是一致的。

3.注意点: 1.可变参数如果出现在参数列表,那么一定是位于参数列表的最后 2.一个方法的参数列表最多只能有一个可变参数 3.如果参数是可变参数,可以传递一个数组过去

3.List集合中的排序

Collections.sort(List)

注意点:使用此种方式对集合排序有前提:List集合中的元素所属的类实现了Comparable接口,重写compareTo方法:用于定义比较规则

如果List集合中的元素所属的类没有实现Comparable接口,此时用Collections.sort(List)会编译报错

如果List集合汇总的元素所属的类已经实现了其排序规则,而现在要求对List集合排序,规则不是其元素已经定义的规则,该如何实现?

比较器:内比较器,外比较器

内比较器:Comparable

外比较器:Comparator

案例:List集合保存User对象,User类中已经定义好排序规则按照id排序,现要求对list集合中的元素排序,按照年龄升序排序

public class User implements Comparable<User>{
private Integer userId;
private String userName;
private Integer age;
public User() {
    super();
    // TODO Auto-generated constructor stub
}
public User(Integer userId, String userName, Integer age) {
    super();
    this.userId = userId;
    this.userName = userName;
    this.age = age;
}
public Integer getUserId() {
    return userId;
}
public void setUserId(Integer userId) {
    this.userId = userId;
}
public String getUserName() {
    return userName;
}
public void setUserName(String userName) {
    this.userName = userName;
}
public Integer getAge() {
    return age;
}
public void setAge(Integer age) {
    this.age = age;
}
@Override
public String toString() {
    return "User [userId=" + userId + ", userName=" + userName + ", age=" + age + "]";
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((userId == null) ? 0 : userId.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    User other = (User) obj;
    if (userId == null) {
        if (other.userId != null)
            return false;
    } else if (!userId.equals(other.userId))
        return false;
    return true;
}
@Override
public int compareTo(User o) {
    return this.userId-o.getUserId();
}
}


public class SortListDemo {
public static void main(String[] args) {
    /*
     * 有一个集合保存了n个user对象,现要求对此
     * 集合中的所有user进行排序,排序规则:根据id升序排列
     */
    User user = new User(23, "a", 23);
    User user1 = new User(1, "a", 25);
    User user2 = new User(33, "a", 13);
    User user3 = new User(5, "a", 22);

    List<User> list = new ArrayList<>();
    list.add(user);
    list.add(user1);
    list.add(user2);
    list.add(user3);

    for (User user4 : list) {
        System.out.println(user4);
    }

    /*
     * 要求根据学生的年龄排序
     */
    Collections.sort(list, new ByAge());
    for (User user4 : list) {
        System.out.println(user4);
    }

}

}

class ByAge implements Comparator<User>{
@Override
public int compare(User o1, User o2) {
    return o1.getAge()-o2.getAge();
}
}

Set集合:不可重复集

实现类:HashSet TreeSet:实现了排序的set集合

Map集合:

用于保存K-V对数据 K值是唯一的,V值可重复

map集合的遍历:

keySet():Set

entrySet():Set

Entry:getKey() getValue()

实现类:HashMap TreeMap

面试题:分数排序 3GB的数据存放的是1000000个学生的分数.排序取出前100名

public class Student implements Comparable<Student> {
private Integer id;
private String name;
private Integer score;
public Student() {
    super();
    // TODO Auto-generated constructor stub
}
public Student(Integer id, String name, Integer score) {
    super();
    this.id = id;
    this.name = name;
    this.score = score;
}
public Integer getId() {
    return id;
}
public void setId(Integer id) {
    this.id = id;
}
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}
public Integer getScore() {
    return score;
}
public void setScore(Integer score) {
    this.score = score;
}
@Override
public String toString() {
    return "Student [id=" + id + ", name=" + name + ", score=" + score + "]";
}
@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}
@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    Student other = (Student) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}
@Override
public int compareTo(Student o) {
    return this.id-o.getId();
}
}

public class SortStudent {
public static void main(String[] args) {
    //创建1000000个学生并存入set集合
    Set<Student> set = new TreeSet<>(new ByScore());

    for(int i=0;i<1000000;i++){
        Student student = new Student(i, "学生"+i, (int)(Math.random()*60000));
        set.add(student);

        if(set.size()>100){
            Iterator<Student> it = set.iterator();
            it.next();
            it.remove();
        }
    }

    for (Student student : set) {
        System.out.println(student);
    }

}

}

class ByScore implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
    return o1.getScore()-o2.getScore();
}
}

IO流

File
RandomAccessFile

构造方法: new RandomAccessFile(File/String,String mode)

mode:r   rw

特点:是基于指针操作的文件操作类,此类的对象可以实现对文件数据的读和写操作

方法:

读数据,写数据方法和IO流中字节流的读写方式一样的。

seek(long pos)

getFilePointer():long

IO流:代码自己下去看笔记

线程

线程的生命状态:5种 新建状态(NEW) 就绪状态(Runnable) 运行状态(Running) 阻塞状态(Blocked) 死亡状态(Dead)

线程的创建:2种方式

方式一:extends Thread

方式二:implements Runnable

两种方式的区别: 继承Thread方式实现了线程和任务的不可分离 实现Runnalbe接口方式实现了线程和任务的分离、

线程的启动:调用Thread类中的start()启动线程

多线程并发访问:

可能出现的问题:多线程并发安全问题,可能出现被污染的数据

如何解决:同步,异步

多线程并发是异步的

解决多线程并发安全问题:线程同步

方式:Synchronized

用法:可以用于修饰方法,修饰代码块

同步的机制:锁机制

修饰方法给调用此同步方法的对象加锁

修饰代码块可以给任意对象加锁,经常用的this

注意点:不能实现同步的情景:

情景一: class T{ public synchronized void test(){} public void demo(){} }

class Test{
    main:
        Thread threadA = new Thread(){
            run:
            T t = new T();
            t.test();
        };
        Thread threadB = new Thread(){
            run:
            T t = new T();
            t.test();
        }
        threadA.start();
        threadB.start();
}

情景二: class T{ public synchronized void test(){} public void demo(){} }

class Test{
    main:
        T t = new T();
        Thread threadA = new Thread(){
            run:
            t.test();
        };
        Thread threadB = new Thread(){
            run:
            t.demo();
        }
        threadA.start();
        threadB.start();
}

同步的互斥性 class T{ public synchronized void test(){} public synchronized void demo(){} }

class Test{
    main:
        T t = new T();
        Thread threadA = new Thread(){
            run:
            t.test();
        };
        Thread threadB = new Thread(){
            run:
            t.demo();
        }
        threadA.start();
        threadB.start();
}

线程池:

创建

Executors.creatFixedThreadPool(int nThread):ExecutorService

将任务提交给线程池:

execute(Runnable)

线程池的关闭:

shutDown():将已经接受到的任务全都执行完,不接受新任务,任务执行完关闭线程池

shutDownNow():List

作用:试图终止正在执行的任务,不执行等待的任务, 并将已经接受但没执行的任务返回给list集合

TCP通信

多线程和Tcp做聊天室项目

反射:实现动态执行

XML

解析:DOM4J SAX

JAVA基础部分-选择题

(单选)1.在Java语言中,字符串“Java程序员”在内存中所占用的字节数是:(D)。

A.10

B.7

C.13

D.14

2.(多选)所谓“水仙花”数是一个整数等于各位数字立方的和,例如:153 = 111+555+333,下面的程序用于输出2~1000内的水仙花数:

for (int n = 2; n <= 1000; n++) { 
    空白处  
    if (s == n) { 
        System.out.println(n); 
    } 
}  

下列选项中,空白处可以填入的代码是:(AC)。 A.int s = 0,  n1 = n;  while (n1 > 0) { int t = n1 % 10;  s += t * t * t;  n1 /= 10; }

B.int s = 0,  n1 = n;  while (n1 > 0) { int t = n1 / 10; s+= t * t * t;  n1 %= 10; }

C.int s = 0;  for(int n1 = n; n1>0;  n1 /= 10) { int t = n1%10;  s += t * t * t; }

D.int s = 0;  for(int n1 = n;  n1>0;  n1 %= 10) { int t = n1 / 10;  s += t * t * t; }

3.下列语句序列执行后,k 的值是 ( D )

  int  x=6, y=10, k=5;
  switch( x % y )
  {
       case 0:  k=x*y;
       case 6:  k=x/y;
       case 12:  k=x-y;
       default:  k=x*y-x;
  }

A.60

B.5

C.0

D.54

4.下列程序

class Test{
    public static void main(String[] args){
        doSomething(1);
        doSomething(1,2);
    }
    //insert code here
}

在程序中插入下列哪一行代码可以编译通过: BD A static void doSomething(int[] args){}

B static void doSomething(int... args){}

C static coid doSomething(int...args,int x){}

D static void doSomething(int x,int...args){}

1.(单选)关于下列代码说法正确的是: A

public class A {
    private int counter = 0; 
    public static int getInstanceCount() { 
        return counter; 
    } 
    public A() { 
        counter++; 
    } 
    public static void main(String[] args) { 
        A a1 = new A(); 
        A a2 = new A(); 
        A a3 = new A();
        System.out.println(A.getInstanceCount()); 
    } 
}

A.该类编译失败

B.输出:1

C.输出:3

D.输出:0

2.试图编译和运行以下代码,将获得什么结果(B)

class Base {
    int i = 99;
    public void amethod() {
        System.out.println("Base.amethod()");
    }
    Base() {
        amethod();
    }
}
public class RType extends Base {
    int i = -1;
    public static void main(String argv[]){
        Base b = new RType();
        System.out.print(b.i+"\t");
        b.amethod();
        RType r = (RType)b;
        System.out.print(r.i+"\t");
    }
    public void amethod(){
        System.out.print("RType.amethod()"+"\t");
    }
}

A RType.amethod -1 RType.amethod -1

B RType.amethod 99 RType.amethod -1

C 99 RType.amethod 99

D 编译时错误(Compile time error)

3、下边程序运行的结果是? ( B )

class Base {
 Base() { System.out.print("Base"); }
}
public class Alpha extends Base {
   public static void main( String[] args ) {
        new Alpha();
        new Base();
  }
 }

A.Base

B.BaseBase

C.程序编译失败.

D.程序运行但没有任何输出

程序题

现有一个字符串"fdasafdasfdasa",现统计出子串"as"出现的次数.

public class CountSubString {
public static void main(String[] args) {
    String str = "fdasafdasfdasas";
    String subStr = "as";
    //统计subStr出现的次数
    /*
     * indexof(String sub,int index)
     */
    int index = 0,count = 0;
    while((index=str.indexOf(subStr, index))!=-1){
        count++;
        index += subStr.length();
    }
    System.out.println(count);

}

}

3.一个数组中只有0,1两种数字,进行排序,0全部在前,1全部在后

public class ZeroOneSort {
public static void main(String[] args) {
    int[] ary = {0,1,1,0,1,0,1,0};
    int index = 0;
    for(int i=0;i<ary.length;i++){
        if(ary[i]==0){
            ary[i] = 1;
            ary[index++] = 0;
        }
    }

    System.out.println(Arrays.toString(ary));
}

}

OOP部分-简答题

1.抽象类和接口的区别

2.静态变量和实例变量的区别?

3.String s = new String("xyz");创建了几个String Object ?

4.字符串连接时为什么推荐使用StringBuffer而不是直接用String+String的方式,请简述原因?

5.final, finally, finalize的区别。