【面试】-Java基础知识

1、Java的工作原理
1) Java源程序(.java)需要通过编译器编译成字节码(.class)文件;
2) Java程序的跨平台主要指字节码可以在任何具有Java虚拟机的设备上运行;
3) Java虚拟机的建立需要针对不同的软硬件平台(处理器、操作系统)做专门的实现。
4) 字节码首先由类装载器加载到Java虚拟机中,其次由字节码校验器检查是否有非法操作,校验通过后再由Java解释器把字节码解释成机器码执行。
5) Java虚拟机采用沙箱模式运行,即把Java程序的代码和数据限制在一定的内存空间里执行,不允许程序访问该内存空间外的内存。


2、八种基本数据类型
这里写图片描述


3、基本数据类型间的转换
1) 自动转换:参与运算的数据类型不一致时,精度低的会自动向精度高的转换。
byte-> short\char\int\long\float\double
short->char\int\long\float\double
char->int\long\float\double
long->float\double
float->double
2) 强制转换:强制转换又叫显示转换,有可能造成数据精度的损失,应慎用。


4、运算符
算术运算符 ++,–,+,-,*,/,%
逻辑运算符 &,|,!,^,&&,||
关系运算符 >,<,==,!=,<=,>=
位运算符 &,|,^,~,>>,<<,>>>


5、switch(表达式)
在Java1.6(包括)之前,表达式只支持能等价成int类型的数据:byte\char\short\int,其他类型均不可以。在Java1.7以后,可以支持String类型的数据。


6、面向对象的特征
1)封装:把对象的全部属性和全部方法结合成一个独立的单位,并尽可能屏蔽对象的内部细节。
2)继承:子类拥有父类的所有非private属性和方法,并且子类中还可以增加新的属性和方法;Java支持单继承多实现
3)重载:同一个类中用相同的方法名定义多个方法,同名方法之间以所带参数个数、参数类型、参数顺序的不同来区分,参数的返回值类型、访问权限、抛出的异常不构成方法重载的标志。
4)覆盖:子类中使用与父类同名的方法,且方法的参数(个数、类型、顺序)和返回值类型完全一样,即子类方法的代码覆盖父类方法的代码。被覆盖的方法不能是私有的。
5)多态:程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定。其实现机制是:父类或接口定义的引用变量可以指向子类或者具体实现类的实例对象。
6)子类在隐藏父类的成员后,往往还要用到父类的成员。在子类中引用被隐藏的父类成员时需要用super指明。
访问父类方法:super.方法名(参数)
访问父类成员:super.成员变量
调用父类构造方法:super(参数)


7、抽象类和接口
1)含有抽象方法的类必须定义成抽象类,抽象类中的方法可以不是抽象方法;
2)抽象类中定义的抽象方法必须在子类中实现,所以,不能有抽象构造方法和抽象静态方法;
3)如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义成抽象类;
4)接口可以说是抽象类的一种特例,接口中的所有方法都必须是抽象的;
5)接口中的方法类型默认为:public abstract,变量类型默认为:public static final;
6)一个类可以实现多个接口,但只能继承一个抽象类。


8、方法调用时参数传递
1)值传递:当方法的参数是基本数据类型时是值传递。值传递传递给方法的是参数的数据值,方法接收实际参数的值,但不改变实际参数的值。
2)引用传递:当方法的参数是对象或者数组时是引用传递。引用传递传递给方法的是参数在内存中的地址,方法中对参数的操作会改变参数的数据值。


9、作用域 public ,private ,protected ,以及不写时的区别
说明:如果在元素前面没有写任何访问修饰符,则表示 friendly。
这里写图片描述


10、异常
1)所有的异常都是由Throwable继承而来,分为Error和Exception两类;
2)Error表示Java运行时系统的内部错误和资源耗尽错误,应用程序不应该抛出这种类型的异常。
3)Exception分为两类,所有RuntimeException类及其子类的实例被称为Runtime异常,不属于该范畴的异常则被称为CheckedException;
4)Java认为CheckedException是可以被处理的异常,所以Java程序必须显式处理这类异常,如果不处理这类异常,编译时就会发生错误而无法编译;
5)空指针异常、数组越界异常、类型转换异常、除数为零等都是RuntimeException。


11、内部类
1)内部类是指将一个类定义在另一个类的内部,甚至方法的内部。
2)内部类可以无条件的访问其内部声明的成员和外部类的成员,外部类不能直接访问内部类的成员。
3)内部类分为静态内部类和非静态内部类,两者的区别如下:
3.1)静态内部类和外部类对象独立,它可以直接创建对象(new Outer.Inner()),也可以通过外部类对象创建对象(outer.new Inner());
3.2)静态内部类只能使用外部类的静态成员,不能使用外部类的非静态成员,而非静态内部类可以使用外部类的所有成员;
3.3)静态内部类中可以定义静态成员和非静态成员,非静态内部类中只能定义非静态成员。
4)匿名类:没有类名的内部类,多用在事件处理的程序中。


12、Java虚拟机运行时数据区
1)程序计数器:每个线程都有自己的程序计数器,它可以看作是线程所执行的字节码的行号指示器;
2)Java虚拟机栈:描述的是java方法执行内存模型,每个方法在执行的同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接、方法出口等信息;
3)本地方法栈:与Java虚拟机栈差不多,区别是Java虚拟机栈是为执行Java方法服务,本地方法栈是为执行Native方法服务;
4)Java堆:被所有线程共享的内存区域,所有对象的实例和数组都在堆上分配存储空间;
5)方法区:也是被所有线程共享的内存区域,用于存储被虚拟机加载的类信息、常量、静态变量等


13、Equals和==的区别
==:比较基本类型变量或者引用类型变量的值是否相等;
equals:比较引用类型变量对应的对象的内容是否相同;

String s1 = "qaz";
String s2 = "qaz";
String s3 = new String("qaz");
System.out.println(s1 == s2);             //true 
System.out.println(s1.equals(s2));         //true
System.out.println(s1 == s3);             //false
System.out.println(s1.equals(s3));         //true

14、String s=new String(“qaz”),创建了几个字符串对象?
1)”qaz”是一个字符串对象(字符串常量),它存放在常量池中;
2)new String(“qaz”)会根据字符串常量”qaz”的内容创建一个字符串对象,存放在堆内存中;
3)在2)执行之前,如果常量池中不存在常量”qaz”,则会在常量池中创建字符串对象”qaz”,否则不用创建。
综上可知答案为:一个或者两个。


15、 如何把一段逗号分隔的字符串转换成一个数组?
1)用String.spilt(“,”);
2)用StringTokenizer,代码如下:

String str = "a,bc,d,efg";
        StringTokenizer tokenizer = new StringTokenizer(str, ",");
        String[] words = new String[tokenizer.countTokens()];
        int i = 0;
        while (tokenizer.hasMoreTokens()) {
            words[i++] = tokenizer.nextToken();
        }

16、Try-catch-finally语句中,finally语句最后执行,即使在try或者catch中已经return了finally语句也会执行;

    public static void main(String[] args) {
        System.out.println(getInt() + "");
    }
    public static int getInt() {
        try {
            return 2;
        } finally {
            return 3;
        }
    }

———–执行结果 3——-


17、类在实例化时成员的初始化顺序
1)初始化父类的静态成员变量和静态代码块;
2)初始化子类的静态成员变量和静态代码块;
3)初始化父类的普通成员变量和代码块;
4)初始化子类的普通成员变量和代码块。


18、原码、反码、补码
1)机器数:一个数在机器中的二进制表示形式叫做机器数,机器数是带符号的,在计算机中用最高位表示符号位,0表示正数,1表示负数。
2)真值:带符号数在计算机中用补码表示,机器数表示的真实数值叫做真值。
3)原码:符号位加上真值的绝对值,比如8位二进制数:
[+1]原=00000001 [-1]原=10000001
4)反码:正数的反码是其本身,负数的反码是符号位不变,其余各位取反:
[+1]反=00000001 [-1]反=11111110
5)补码:正数的补码是其本身,负数的补码是在反码的基础上加一:
[+1]补=00000001 [-1]补=11111111


19、左移、右移、无符号右移
1)左移:向左移动指定位,符号位跟着移动,超出高位截断,低位补0;
2)右移:向右移动指定位,符号位跟着移动,超出低位截断,高位补符号位;
3)无符号右移:向右移动指定位,符号位跟着移动,超出低位截断,高位补0;


20、Java垃圾回收机制
1)垃圾回收器的任务是回收垃圾对象所占用的空间供新的对象使用;
2)如果一个对象没有任何引用与之关联,那么这个对象就成了可回收的对象;
3)引用计数法和可达性分析法来判断对象是否还有引用与之关联;
4)比较常见的将对象判定为可回收对象的情况:
1、显式的将引用赋值为null;
2、将已经指向某个对象的引用指向新的对象;
3、局部引用指向的对象
4、只有弱引用与之关联的对象;
5)典型的垃圾回收算法:
1、Mark-Sweep(标记-清除法):标记阶段标记所有需要被回收的对象,清除阶段回收所有被标记对象占用的空间,这种方法简单但容易产生内存碎片;
2、Copying(复制)算法:将内存划分为大小相同的两块,每次使用其中一块。当使用的这一块内存满了之后,就将活着的对象复制到另一块内存上,然后回收整块内存。虽然解决了内存碎片问题,但可以使用的内存缩减为原来的一半;
3、Mark-Compact(标记-整理法):标记阶段标记所有需要回收的对象,整理阶段将活着的对象移到一端,然后清除边界以外的内存;
4、Generational Collection(分代收集)算法:该算法是目前大部分JVM垃圾回收器采用的算法。它将堆内存划分为老年代和新生代,每次垃圾回收时老年代只有少数对象需要回收,新生代中大部分对象都需要回收。老年代采用标记-整理法,新生代采用复制法。


21、对于JVM内存配置参数:-Xmx10240m -Xms10240m -Xmn5120m -XX:SurvivorRatio=3,其中最小内存值和Survivor区总大小分别是(10240)和(2048)。
1)-Xmx:最大堆大小;
2)-Xms:初始堆大小,即为最小内存值;
3)-Xmn:年轻代大小,年轻代由一个Eden区和两个Survivor区组成;
4)-XX:SurvivorRatio:年轻代中Eden区与Survivor区的大小比值;


22、 Java内存模型
Java内存模型规定了JVM有主内存,主内存是多个线程共享的。每个线程都有自己的工作内存,工作内存中保存了该线程用到的变量的主内存拷贝副本,线程对变量的所有操作都必须在工作内存中进行,而不能直接读写主内存中的变量。
Java内存模型定义了以下八种操作来完成主内存和工作内存之间的交互:
(1)Lock(锁定):作用于主内存变量,把一个变量标识为一个线程独占的状态;
(2)Unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才能被其他线程锁定;
(3)Read(读取):作用于主内存变量,把一个变量从主内存传输到工作内存;
(4)Load(载入):作用于工作内存,把从主内存得到的变量值赋给工作内存中的变量副本;
(5)Use(使用):作用于工作内存,把工作内存变量副本的值传递给执行引擎;
(6)Assign(赋值):作用于工作内存变量,把从执行引擎接收到的值赋给工作内存中的变量副本;
(7)Store(存储):作用于工作内存,把工作内存中变量副本的值传输到主内存;
(8)Write(写入):作用于主内存,把从工作内存得到的变量副本的值赋给主内存中的变量


23、线程与进程的区别
1)进程是资源的组织单位,进程中有一个包含了程序内容和数据的地址空间,不同进程的地址空间是相互隔离的;
2)线程是CPU的调度单位,表示的是程序的执行流程,线程有自己的程序计数器、寄存器、栈和帧等;
3)引入线程的动机在于阻塞式i/o的存在,当一个线程执行的i/o操作被阻塞时,同一进程的其他线程可以用CPU来进行计算,从而提高了应用的执行效率。


24、创建线程的方法
1)通过继承Thread类创建线程;
2)通过实现Runnable接口创建线程类;
3)使用Callable和FutureTask创建线程类。


25、线程的状态转换
1)新建状态:程序使用new关键字新建一个线程后,该线程处于新建状态;
2)新建—>就绪:处于新建状态的线程调用start()方法;
3)就绪—>运行:处于就绪状态的线程得到处理器资源进入运行状态;
4)运行—>就绪:失去处理器资源或者调用yield()方法;
5)运行—>阻塞:1、sleep(),2、IO阻塞,3、等待同步锁,4、suspend()方法(易导致死锁);
6)运行—>死亡:1、run()或call()方法执行完成,线程正常结束,2、线程抛出一个未捕获的Exception或Error,3、调用stop()方法(易导致死锁);
7)阻塞—>就绪:1、sleep()时间到,2、IO方法返回,3、获得同步锁,4、resume()。


26、线程控制
1)join()方法:调用join()方法的线程完成run()后再执行join()方法后面的代码;
2)后台线程:在后台运行,为其他线程提供服务的线程。JVM垃圾回收线程就是典型的后台线程。如果所有的前台线程都死亡了,后台线程会自动死亡;
3)sleep()方法:让线程暂停一段时间,线程转入阻塞状态;
4)yield()方法:让线程暂停一下,线程转入就绪状态;


27、互斥同步
1)互斥同步是一种常见的并发正确性保障手段。同步是指在多个线程并发访问共享数据时,共享数据在同一时刻只被一个或者几个(使用信号量的时候)线程访问。
2)互斥是实现同步的一种手段是方法,同步是互斥的目的。临界区、互斥量、信号量是实现互斥的主要方式;
3)synchronized关键字和重入锁ReentrantLock是实现同步的基本手段,相比synchronized,ReentrantLock增加了一些高级功能,主要有一下3项:
1、等待可中断:当持有锁的线程长期不释放锁的时候,正在等待的线程可以选择放弃等待;
2、公平锁:多个线程在等待同一个锁时,必须按照申请锁的时间顺序来依次获得锁。Synchronized锁是非公平的,ReentrantLock默认也是非公平的,但可以使用带布尔值的构造函数要求使用公平锁;
3、ReentrantLock锁可以绑定多个条件,即一个ReentrantLock对象可以同时绑定多个Condition对象。


28、线程协作
方式一:wait()、notify()和notifyAll()
1)wait()、notify()和notifyAll()是Object类中的方法,并且为final方法;
2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线程必须拥有此对象的monitor;
3)调用某个对象的notify()方法能够唤醒一个正在等待这个对象的monitor的线程;
4)调用notifyAll()方法能够唤醒所有正在等待这个对象的monitor的线程;
5)这三个方法必须在同步块或者同步方法中执行,notify()和notifyAll()方法只是唤醒等待该对象的monitor的线程,并不决定哪个线程能够获取到monitor。

方式二:使用Condition的await()、signal()和signalAll()
1)采用这种方式实现线程间协作更加安全高效;
2)Condition是一个接口,基本方法是await(),signal(),signalAll();
3)Condition依赖于Lock接口,生成一个Condition的基本代码是lock. new Condition;
4)Condition的三个基本方法跟wait()、notify()、notifyAll()对应;
5)调用这三个方法都必须在lock的保护之内,就是说必须在lock.lock()和lock.unlock()之间才可以使用


29、HashMap和HashTable的区别
1)HashTable继承Dictionary,HashMap继承AbstractMap;
2)HashTable的方法是同步的,而HashMap的方法不是同步的,效率上HashMap高于HashTable;
3)HashMap允许key,value为空,HashTable不允许。


30、sleep()和wait()的区别
1)sleep()是定义在Thread类中的方法,wait()是定义在Object类中的方法;
2)wait()方法只能在同步控制方法或同步控制块中调用,sleep()可以在任何地方使用;
3)sleep()方法没有释放锁,wait()方法释放了锁,使得其他线程可以使用同步代码块;
4)sleep()方法不出让系统资源,wait()方法出让系统资源。


31、synchronized关键字
1)synchronized既保证了多线程的并发有序性,又保证了多线程的内存可见性。
2)一个线程执行临界区代码过程如下:1 获得同步锁;2 清空工作内存;3 从主内存拷贝变量副本到工作内存;4 对这些变量进行计算;5 将变量从工作内存写回到主存;6 释放锁。
3)public synchronized void method()这种情况,锁就是方法所在的对象,public static synchronized void method(),那么锁就是这个方法所在的类。


32、volatile关键字
1)volatile只能保证多线程的内存可见性,不能保证多线程的执行有序性
2)对于volatile修饰的变量,jvm虚拟机只是保证从主内存加载到线程工作内存的值是最新的,并不能解决并发带来的问题。

例如线程1,线程2 在进行read,load 操作中,发现主内存中count的值都是5,那么都会加载这个最新的值5。在线程1对count进行修改之后,会write到主内存中,主内存中的count变量就会变为6。线程2由于已经进行read,load操作,在进行运算之后,也会更新主内存count的变量值为6。即使使用了volatile关键字,也没能解决并发带来的问题。


33、 写一个单例模式

public class SingleInstance {
    private SingleInstance() {}
    public static SingleInstance getInstance() {
        return SingleInstanceHolder.INSTANCE;
    }
    private static class SingleInstanceHolder {
        private final static SingleInstance INSTANCE = new SingleInstance();
    }
}
public class SingleInstance {
    private volatile static SingleInstance sInstance;
    private SingleInstance() {
    }
    public static SingleInstance getInstance() {
        if (sInstance == null) {
            synchronized (SingleInstance.class) {
                if (sInstance == null) {
                    sInstance = new SingleInstance();
                }
            }
        }
        return sInstance;
    }
}
public enum SingleInstance {
    INSTANCE;
    private SingleInstance() {
    }
}

34、final finally finalize 区别
1)final:Java中的关键字、修饰符,如果一个类被声明为final,意味着它不能派生出新的子类,不能作为父类被继承,因此一个类不能同时声明为abstract和final;被声明为final的变量必须在声明时给定初始值,在以后的使用中只能读取不能修改;被声明为final的方法只能使用,不能重载。
2)finally:try-catch-finally异常处理语句的一部分,finally结构里的代码总会执行,而不管有无异常发生,关闭数据库连接的close()方法通常放在finally中。
3)finalize:Java中的一个方法,在Object类中定义的,finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。


35,Linux下权限对应的数字为:
r =4, w =2, x =1
6就是rw-
4就是r–
5就是r-x


36,TCP三次握手
简化一下,客户端发送X,服务器发送Y。三次握手分别是:
客户端:发送X
服务端:发送Y, 确认X+1
客户端:发送X+1,确认Y+1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值