Java基础知识

4.1 Java基本概念

4.1.1 Java语言的有点

  • Java是纯面向对象的语言;
  • 平台无关性;一次编译,到处运行;
  • Java提供多种内置库;
  • 提供web应用开发的支持;
  • 具有较好的安全性和健壮性;

java语言是c++改进并重新设计而来。

4.1.2 Java与C/C++有什么异同

  • java是解释型语言:程序由Java编译器编译成字节码,然后由JVM执行。C/C++是编译型语言,源代码编译和链节后生成二进制代码。Java比C/C++慢,但是跨平台。
  • Java纯面向对象,C++面向过程和对象,可以定义全局变量和全局函数。
  • Java没有指针;
  • Java不支持多继承;
  • 自动gc

4.1.3 为什么又public static void main(String[] args)方法

  • Java程序的入口方法;
  • static表明该方法在静态存储区,类加载后就可以访问,类名.方法名;
  • args是命令行下交互的方式;

引申:

  • main()方法的其他定义格式:
    – static public void main(String[] args)
    – public static final void main(String[] args)
    – static public synchronized void main(String[] args)
  • 一个.java文件中可以多个main()方法吗?
    – 只有和文件名相同的用public修饰的类的main才可以作为程序入口。

4.1.4 静态块在类被加载时就调用

public class Test {

    static {
        System.out.println("hello world1");
    }

    public static void main(String[] args) {
        System.out.println("hello world2");
    }
}

结果

hello world1
hello world2

4.1.5 Java程序初始化的顺序

对象实例化之前,所在类的所有成员变量都会进行初始化。

三个原则:

  • 静态对象(变量)优先初始化;静态只初始化一次。
  • 父类优先子类初始化;
  • 按成员变量定义顺序初始化。

例:
父类静态变量;
父类静态代码块;
子类静态变量;
子类静态代码块;
父类非静态变量;
父类非静态代码块;
父类构造函数;
子类非静态变量;
子类非静态代码块;
子类构造函数。

4.1.6 Java的作用域

4.1.7 一个Java文件是否可以定义多个类

可以。但是只有一个类用public修饰,并且名字与文件名相同。
javac编译的时候会生成多个.class文件。

4.1.8 什么是构造函数

  • 构造函数名与类名相同,且没有返回值;
  • 每个类可以有多个构造函数;
  • 构造函数可以有0个或多个参数;
  • 构造函数伴随new操作调用,必须由系统调用。
  • 构造函数完成对象初始化;
  • 构造函数不能被继承和覆盖,但可以重载;
  • 子类可通过uper显示调用父类构造函数;
  • 父类和子类都没有构造函数的时候,编译器会给父类和子类生成一个无参构造函数;
  • 构造函数的修饰符与当前类的修饰符相同。

4.1.9 为什么接口没有实现方法

  • 接口只包含方法的定义,不包含方法的实现;
  • java8开始,接口默认方法是静态方法;
  • 接口成员的修饰符都是public
  • 接口常量值默认public static final

4.1.10 Java中的clone方法作用

  • Java才采用基本类型(int, double, char)的时候都是值传递;
  • 其他类型都按引用传递;
class Obj {
    private int aInt = 0;
    public int getaInt(){
        return aInt;
    }

    public void setAInt(int init1) {
        this.aInt = init1;
    }

    public void  changeInt() {
        this.aInt = 1;
    }
}
public class TestRef {

    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = a;
        b.changeInt();
        System.out.println("a: "+ a.getaInt());
        System.out.println("b: "+b.getaInt());
    }
}

结果:

a: 1
b: 1
  • 使用clone()方法的步骤:
    – 实现Cloneable()接口,Cloneable()接口是标识接口,没有任何接口方法;
    – 在Object类中重写clone()方法;
    – 在clone()方法中调用super.clone()方法。调用的是Obejct类的clone()方法;
    – 把浅复制的引用指向原型对象新的克隆体。
class Obj implements Cloneable {
    private int aInt = 0;
    public int getaInt(){
        return aInt;
    }

    public void setAInt(int init1) {
        this.aInt = init1;
    }

    public void  changeInt() {
        this.aInt = 1;
    }

    public Object clone(){
        Object o = null;
        try {
            o = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return o;
    }

}
public class TestRef {

    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = (Obj)a.clone();
        b.changeInt();
        System.out.println("a: "+ a.getaInt());
        System.out.println("b: "+b.getaInt());
    }
}

结果

a: 0
b: 1

当类中只有一些基本数据时,采用以上方法即可;
当类中包含对象时,就只能深复制

class Obj implements Cloneable {
    private Date birth = new Date();
    public Date getBirth(){
        return birth;
    }

    public void setAInt(Date birth) {
        this.birth = birth;
    }

    public void  changeDate() {
        this.birth.setMonth(4);
    }

    public Object clone(){
        Obj o = null;
        try {
            o = (Obj)super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        //实现深复制
        o.birth = (Date)this.getBirth().clone();
        return o;
    }

}
public class TestRef {

    public static void main(String[] args) {
        Obj a = new Obj();
        Obj b = (Obj)a.clone();
        b.changeDate();
        System.out.println("a = " + a.getBirth());
        System.out.println("b = " + b.getBirth());
    }
}

结果

a = Wed Sep 25 18:01:03 CST 2019
b = Sat May 25 18:01:03 CST 2019
  • 浅复制与深复制的区别
    – 浅复制只考虑复制的对象,而不考虑被复制对象引用的其他对象;
    – 深复制不仅复制对象,还复制对象引用的对象。

4.1.11 什么是反射机制?

  • 反射功能
    – 得到一个对象所属的类;
    – 得到一个类的所有成员变量和方法;
    – 在运行时创建对象(重要,代码如下);
    – 在运行时调用对象的方法;
class Base {
    public void f() {
        System.out.println("Base");
    }
}
class Sub extends Base {
    public void f() {
        System.out.println("Sub");
    }    
}
public class Test {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("Sub");
            Base b = (Base)c.newInstance();
            b.f();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

结果:

Sub
  • 获取类的方法
    – Class.forName(“类的路径”);
    – 类名.class;
    – 实例.getClass()

  • Java创建对象的方式:
    – 通过new实例化一个对象;
    – 通过反射机制创建对象;
    – 通过clone()方法创建对象;

4.6 异常处理

4.6.1 finally块什么时候执行

  • finally块的作用就是保证无论什么情况下一定会执行;
    如下所示,finally一定是在方法里执行了。
public class Test3 {
    public static int testFinally() {
        try {
            return 1;
        } catch (Exception e) {
            return 0;
        } finally {
            System.out.println("execute finally");
        }
    }

    public static void main(String[] args) {
        int result = testFinally();
        System.out.println(result);
    }
}

结果:

execute finally
1
  • 如果finally有返回值,会覆盖前面的返回值;
public class Test3 {
    public static int testFinally() {
        try {
            return 1;
        } catch (Exception e) {
            return 0;
        } finally {
            System.out.println("execute finally");
            return 3;
        }
    }

    public static void main(String[] args) {
        int result = testFinally();
        System.out.println(result);
    }
}

结果

execute finally
3
  • 对基本数据类型,finally中改变其值不会有影响,对引用类型会有影响。
public class Test3 {
    public static int testFinally1() {
        int result = 1;
        try {
            result = 2;
            return result;
        } catch (Exception e) {
            return 0;
        } finally {
            result = 3;
            System.out.println("execute finally1");
        }
    }

    public static StringBuffer testFinally2(){
        StringBuffer sb = new StringBuffer("Hello");
        try {
            return sb;
        } catch (Exception e) {
            return null;
        } finally {
            sb.append(" World");
            System.out.println("execute finally2");
        }
    }

    public static void main(String[] args) {
        int resultVal = testFinally1();
        System.out.println(resultVal);
        StringBuffer resultRef = testFinally2();
        System.out.println(resultRef);
    }
}

结果:

execute finally1
2
execute finally2
Hello World

引申:finally中的代码一定会执行吗?

否,下面是两个例子;

  • 程序进入try之前就出现异常,不会执行
public class Test3 {
    public static int testFinally() {
        int result = 1/0;
        try {
            result = 2;
            return result;
        } catch (Exception e) {
            return 0;
        } finally {
            result = 3;
            System.out.println("execute finally1");
        }
    }
}
  • 在try中强制退出也不会
public class Test3 {
    public static void testFinally() {
        try {
            System.out.println("try block");
            System.exit(0);
        } catch (Exception e) {
            System.out.println(" catch block");;
        } finally {
            System.out.println("finally block");
        }
    }

    public static void main(String[] args) {
        testFinally();
    }
}

4.9 Java Collections

4.9.1 Java Collections框架是什么

List、Set、Stack、Queue接口均继承自Collection接口。

  • Set接口
    元素不能重复,因此每个元素定义了equals()方法保证唯一性。TreeSet有序,HashSet无序。
  • List接口
    有序的,具体实现有ArrayList, LinkedList和Vector.
  • Map接口
    值可以重复,但是键值唯一。
    HashMap基于散列表实现,采用对象的hashCode快速查询。LinkedHashMap采用列表维护内部的顺序。TreeMap基于红黑树实现,内部元素按需排列。

4.9.2 什么是迭代器

  • 迭代器使用示例:
public class IteratorTest {
    public static void main(String[] args) {
        List<String> ll = new ArrayList<String>();
        ll.add("first");
        ll.add("second");
        ll.add("thrid");
        ll.add("fourth");
        for (Iterator<String> iter=ll.iterator(); iter.hasNext();) {
            String str = iter.next();
            System.out.println(str);
        }
    }
}
  • 迭代器failed-fast原因:当调用容器的iterator()方法返回Iterator对象时,把容器中包含对象的个数赋值给一个expectedModCount, 在调用next()方法的时候会比较容器实际对象数modCount和expectedModCount是否相等,不相等则抛出ConcurrentModificationExpection.

引申

  1. 多线程情况下:JDK1.5以后ConcurrentHashMap和CopyOnWriteArrayList是线程安全的容器;
  2. Iterator和ListIterator的区别?
    Iterator只能正向遍历集合。ListIterator继承自Iterator,可以从两个方向遍历List,同时支持元素修改。

ArrayList、Vector和LinkedList的区别

  • ArrayList 底层数组实现 默认扩容1.5倍 随机访问O(1) 插入O(n);
  • Vector 底层数组实现 synchronization同步 默认扩容2倍 性能低于ArrayList。
  • LinkedList 底层双向列表 访问O(n) 插入O(1) 线程不安全。

HashMap、HashTable、TreeMap和WeakHashMap有哪些区别?

  • HashMap 和HashTable的区别
    – HashMap是HashTable的轻量级实现,HashMap允许插入一个key为null的值,在0位置,HashTable不可以;
    – HashMap中是containsValue和containsKey方法,HashTable是contains方法;
    – HashTable是线程安全的,使用了同步控制;
    – HashTable使用Enumeration,HashMap使用Iterator
    – HashMap和HashTable的hash/rehash方法几乎一致。
    – HashTable大小默认11,扩容是old2+1, HashMap默认16,扩容old2;
  • TreeMap实现了sortedMap,能够保存的记录根据键排序。
  • WeakHashMap的键采用弱引用,键不需要时GC就回收。

常见面试题

  • HashTable中的同步?
    同时只能一个线程可以修改hash表。
  • 如何实现HashMap的同步?
    Map m = Collections.synchronizedMap(new HashMap())

4.9.6 Collection和Collections的区别

  • Collection是一个集合接口;
  • Collections是一个服务Collection的包装类。

4.10 多线程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值