java基础复习2

系列文章目录


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、String s = "Hello";s = s + " world!";这两行代码执行后,原始的
String 对象中的内容到底变了没有?

因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象

public class Demo {
private String s;
... public Demo {
s = "Initial Value";
}
... }

结果:没有

二、是否可以继承 String 类?

String 类是 final 类故不可以继承。

三.String s = new String("xyz");创建了几个 String Object? 二者之间有什么区别? xyz 是字面量

代码如下(示例):

String a=new String("a")

结果:两个

一个放在常量区,不管写多少遍,都是同一个。New String 每写一遍,就创建一个新。


四.String 和 StringBuffer 的区别

上面的代码效率很高,因为只创建了一个 StringBuffer 对象,而下面的代码效率很低,因为创建了 101 个对象。

StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{
sbf.append(i);
}


String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}

五.try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会
不会被执行,什么时候被执行,在 return 前还是后?

会执行,在 return 前执行。
我的答案是在 return 中间执行,参看下一题的讲解。

public class Test {
public static void main(String[] args) {
System.out.println(new Test().test());;
}
static int test()
{
int x = 1;
try
{
return x;//产生中断 保存断点 压栈 x=1
}
finally
{
System.out.println(++x);//接着恢复断点 弹栈 x=1
}
}
}

结果:1


六.final, finally, finalize 的区别。

final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成 final 类型,例如,一段代码……
finally 是异常处理语句结构的一部分,表示总是执行。


七.运行时异常与一般异常有何异同?

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

public static void test2() throws Exception{
        throw new Exception();
    }
    


    public static void test3() {
        throw new RuntimeErrorException();
    }
    }

结果:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The constructor RuntimeErrorException() is undefined

    at demo.Text.test3(Text.java:71)
    at demo.Text.main(Text.java:11)
 

异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java 编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。


八.error 和 exception 有什么区别?

error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 exception 表示
一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。


九.error 和 exception 有什么区别?

error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 exception 表示
一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。


十.给我一个你最常见到的 runtime exception。

rithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException,
IllegalMonitorStateException, IllegalPathStateException, IllegalStateException, ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFORMatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException


十一.sleep() 和 wait() 有什么区别?

sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会
自动恢复。调用 sleep 不会释放对象锁。 wait 是 Object 类的方法,对此对象调用 wait 方法导致本线程放弃对象锁,进入等待此对象的
等待锁定池,只有针对此对象发出 notify 方法(或 notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。


sleep 就是正在执行的线程主动让出 cpu,cpu 去执行其他线程,在 sleep 指定的时间过后,cpu 才会回到这个线程上继续往下执行,如
果当前线程进入了同步锁,sleep 方法并不会释放锁,即使当前线程使用 sleep 方法让出了 cpu,但其他被同步锁挡住了的线程也无法
得到执行。wait 是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运
行,只有其他线程调用了 notify 方法(notify 并不释放锁,只是告诉调用过 wait 方法的线程可以去参与获得锁的竞争了,但不是马上
得到锁,因为锁还在别人手里,别人还没释放。如果 notify 方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在 notfiy
方法后增加一个等待和一些代码,看看效果),调用 wait 方法的线程就会解除 wait 状态和程序可以再次得到锁后继续向下运行。对于
wait 的讲解一定要配合例子代码来说明,才显得自己真明白。

package com.huawei.interview;
public class MultiThread {
public static void main(String[] args) {
new Thread(new Thread1()).start();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Thread2()).start();
}
private static class Thread1 implements Runnable
{
@Override public void run() {
//由于这里的 Thread1 和下面的 Thread2 内部 run 方法要用同一对象作为监视器,我们这里不能用 this,因为在 Thread2 里面的 this 和
这个 Thread1 的 this 不是同一个对象。我们用 MultiThread.class 这个字节码对象,当前虚拟机里引用这个变量时,指向的都是同一个对
象。
synchronized (MultiThread.class) {
System.out.println("enter thread1...");
System.out.println("thread1 is waiting");
try {


//释放锁有两种方式,第一种方式是程序自然离开监视器的范围,也就是离开了 synchronized 关键字管辖的代码范围,
另一种方式就是在 synchronized 关键字管辖的代码内部调用监视器对象的 wait 方法。这里,使用 wait 方法释放锁。

MultiThread.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("thread1 is going on...");
System.out.println("thread1 is being over!");
}
}
}
private static class Thread2 implements Runnable
{
@Override public void run() {
synchronized (MultiThread.class) {
System.out.println("enter thread2...");
System.out.println("thread2 notify other thread can release wait status..");


//由于 notify 方法并不释放锁, 即使 thread2 调用下面的 sleep 方法休息了 10 毫秒,但 thread1 仍然不会执行,因为 thread2 没有释放
锁,所以 Thread1 无法得不到锁。


MultiThread.class.notify();
System.out.println("thread2 is sleeping ten millisecond...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("thread2 is going on...");
System.out.println("thread2 is being over!");
}
}
}
}


十二.同步和异步有何异同,在什么情况下分别使用他们?举例说明。


如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那
么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很
多情况下采用异步途径往往更有效率。


十三.当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对象的其它方法?


分几种情况:


1.其他方法前是否加了 synchronized 关键字,如果没加,则能。
2.如果这个方法内部调用了 wait,则可以进入其他 synchronized 方法。
3.如果其他个方法都加了 synchronized 关键字,并且内部没有调用 wait,则不能。



十四.多线程有几种实现方法?同步有几种实现方法?


多线程有两种实现方法,分别是继承 Thread 类与实现 Runnable 接口
同步的实现方面有两种,分别是 synchronized,wait 与 notify
wait():使一个线程处于等待状态,并且释放所持有的对象的 lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException 异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤
醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。



十五.启动一个线程是用 run()还是 start()?

启动一个线程是调用 start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法
是该线程所关联的执行代码。


十六. 线程的基本概念、线程的基本状态以及状态之间的关系


Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态(图源


《Java 并发编程艺术》4.1.4 节)。

线程在生命周期中并不是固定处于某一个状态而是随着代码的执行在不同状态之间切换。Java 线程
状态变迁如下图所示:

操作系统隐藏 Java 虚拟机(JVM)中的 RUNNABLE 和 RUNNING 状态,它只能看到 RUNNABLE 状态
(图源:HowToDoInJava:Java Thread Life Cycle and Thread States),所以 Java 系统一般将
这两个状态统称为 RUNNABLE(运行中) 状态 。
操作系统隐藏 Java 虚拟机(JVM)中的 RUNNABLE 和 RUNNING 状态,它只能看到
RUNNABLE 状态,所以 Java 系统一般将这两个状态统称为 RUNNABLE(运行中) 状态 。

当线程执行 wait() 方法之后,线程进入 WAITING(等待)状态。进入等待状态的线程需要依靠其他线程的通
知才能够返回到运行状态,而 TIME
_WAITING(超时等待) 状态相当于在等待状态的基础上增加了超时限制,比
如通过 sleep(long millis) 方法或 wait(long millis) 方法可以将 Java 线程置于 TIMED WAITING 状态。
当超时时间到达后 Java 线程将会返回到 RUNNABLE 状态。当线程调用同步方法时,在没有获取到锁的情况下,
线程将会进入到 BLOCKED(阻塞) 状态。线程在执行 Runnable 的 run()方法之后将会进入到 TERMINATED
(终止) 状态。

十七.简述 synchronized 和 java.util.concurrent.locks.Lock 的异同 ?


主要相同点:Lock 能完成 synchronized 所实现的所有功能
主要不同点:Lock 有比 synchronized 更精确的线程语义和更好的性能。synchronized 会自动释放锁,而 Lock 一定要求程序员手工释放,
并且必须在 finally 从句中释放。Lock 还有更强大的功能,例如,它的 tryLock 方法可以非阻塞方式去拿锁。
举例说明(对下面的题用 lock 进行了改写):


package com.zking.interview;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ThreadTest {
private int j;
private Lock lock = new ReentrantLock();
public static void main(String[] args) {
ThreadTest tt = new ThreadTest();
for(int i=0;i<2;i++)
{
new Thread(tt.new adder()).start();
new Thread(tt.new subtractor()).start();
}
}
private class subtractor implements Runnable
{
@Override public void run() {
while(true)
{
/*synchronized (ThreadTest.this) {
System.out.println("j--=" + j--);
成 就 梦 想 时 代
卓京教育面试宝典 2022 版【Java 基础】 第 18 页 共 24 页
//这里抛异常了,锁能释放吗?
}*/
lock.lock();
try
{
System.out.println("j--=" + j--);
}finally
{
lock.unlock();
}
}
}
}
private class adder implements Runnable
{
@Override public void run() {
while(true)
{
/*synchronized (ThreadTest.this) {
System.out.println("j++=" + j++);
}*/
lock.lock();
try
{
System.out.println("j++=" + j++);
}finally
{
lock.unlock();
}
}
}
}
}



十八.设计 4 个线程,其中两个线程每次对 j 增加 1,另外两个线程对 j 每次减少 1。写
出程序。


以下程序使用内部类实现线程,对 j 增减的时候没有考虑顺序问题。
public class ThreadTest1


十九.ArrayList 和 LinkedList 的区别


ArrayList 和 LinkedList 在性能上各有优缺点,都有各自所适用的地方,总的说来可以描述如下:


1.对 ArrayList 和 LinkedList 而言,在列表末尾增加一个元素所花的开销都是固定的。对 ArrayList 而言,主要是在内部数组中增加一项,
指向所添加的元素,偶尔可能会导致对数组重新进行分配;而对 LinkedList 而言,这个开销是统一的,分配一个内部 Entry 对象。
2.在 ArrayList 的中间插入或删除一个元素意味着这个列表中剩余的元素都会被移动;而在 LinkedList 的中间插入或删除一个元素的开销是固定的。
3.LinkedList 不支持高效的随机元素访问。
4.ArrayList 的空间浪费主要体现在在 list 列表的结尾预留一定的容量空间,而 LinkedList 的空间花费则体现在它的每一个元素都需要消
耗相当的空间


可以这样说:当操作是在一列数据的后面添加数据而不是在前面或中间,并且需要随机地访问其中的元素时,使用 ArrayList 会提供比较好
的性能;当你的操作是在一列数据的前面或中间添加或删除数据,并且按照顺序访问其中的元素时,就应该使用 LinkedList 了


二十.HashMap 和 Hashtable 的区别


(条理上还需要整理,也是先说相同点,再说不同点)
HashMap 是 Hashtable 的轻量级实现(非线程安全的实现),他们都完成了 Map 接口,主要区别在于 HashMap 允许空(null)键值(key), 由于非线程安全,在只有一个线程访问的情况下,效率要高于 Hashtable。
HashMap 允许将 null 作为一个 entry 的 key 或者 value,而 Hashtable 不允许。
HashMap 把 Hashtable 的 contains 方法去掉了,改成 containsvalue 和 containsKey。因为 contains 方法容易让人引起误解。
Hashtable 继承自 Dictionary 类,而 HashMap 是 Java1.2 引进的 Map interface 的一个实现。
最大的不同是,Hashtable 的方法是 Synchronize 的,而 HashMap 不是,在多个线程访问 Hashtable 时,不需要自己为它的方法实现同步,
而 HashMap 就必须为之提供外同步。
Hashtable 和 HashMap 采用的 hash/rehash 算法都大概一样,所以性能不会有很大的差异。
就 HashMap 与 HashTable 主要从三方面来说。
一.历史原因:Hashtable 是基于陈旧的 Dictionary 类的,HashMap 是 Java 1.2 引进的 Map 接口的一个实现
二.同步性:Hashtable 是线程安全的,也就是说是同步的,而 HashMap 是线程序不安全的,不是同步的
三.值:只有 HashMap 可以让你将空值作为一个表的条目的 key 或 value 35.List, Set, Map 是否继承自 Collection 接口?
List,Set 是,Map 不是



二十一.List、Map、Set 三个接口,存取元素时,各有什么特点?


List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存 key-value 值,value 可多值。
HashSet 按照 hashcode 值的某种运算方式进行存储,而不是直接按 hashCode 值的大小进行存储。例如,"abc" ---> 78,"def" ---> 62,"xyz"
---> 65 在 hashSet 中的存储顺序不是 62,65,78。LinkedHashSet 按插入的顺序存储,那被存储对象的 hashcode 方法还有什么作用呢?学
员想想!hashset 集合比较两个对象是否相等,首先看 hashcode 方法是否相等,然后看 equals 方法是否相等。new 两个 Student 插入到
HashSet 中,看 HashSet 的 size,实现 hashcode 和 equals 方法后再看 size。
同一个对象可以在 Vector 中加入多次。往集合里面加元素,相当于集合里用一根绳子连接到了目标对象。往 HashSet 中却加不了多次
的。



二十二.去掉一个 List 集合中重复的元素


public class Demo5 {
public static void main(String[] args) {
List list = new ArrayList<>();
// list.add("a");
// list.add("b");
// list.add("c");
// if(!list.contains("b")) {
// list.add("b");
// }
// System.out.println(list);
list.add(new Student("zs", 16));
list.add(new Student("wyf", 18));
list.add(new Student("hzl", 17));
if (!list.contains(new Student("wyf", 18))) {
list.add(new Student("wyf", 18));
}
for (Object object : list) {
System.out.println(object);
}
}
}
class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}


public void setAge(int age) {
this.age = age;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
@Override public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.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 (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
 


二十三.Collection 和 Collections 的区别。


Collection 是集合类的上级接口,继承与他的接口主要有 Set 和 List. Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。



二十四.Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是
equals()? 它们有何区别?


Set 里的元素是不能重复的,元素重复与否是使用 equals()方法进行判断的。
equals()和==方法决定引用值是否指向同一对象 equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。



二十五.两个对象值相同(x.equals(y) == true),但却可有不同的 hash code,这句话对
不对?


对。
如果对象要保存在 HashSet 或 HashMap 中,它们的 equals 相等,那么,它们的 hashcode 值就必须相等。
如果不是要保存在 HashSet 或 HashMap,则与 hashcode 没有什么关系了,这时候 hashcode 不等是可以的,例如 arrayList 存储的对象就
不用实现 hashcode,当然,我们没有理由不实现,通常都会去实现的。



二十六.java 中有几种类型的流?JDK 为每种类型的流提供了一些抽象类以供继承,请说出
他们分别是哪些类?


字节流,字符流。字节流继承于 InputStream OutputStream,字符流继承于 Reader ,Writer。在 java.io 包中还有许多其他的流,主要
是为了提高性能和使用方便。



二十七.什么是 java 序列化,如何实现 java 序列化?


我们有时候将一个 java 对象变成字节流的形式传出去或者从一个字节流中恢复成一个 java 对象,例如,要将 java 对象存储到硬盘或者
传送给网络上的其他计算机,这个过程我们可以自己写代码去把一个 java 对象变成某个格式的字节流再传输,但是,jre 本身就提供了
这种支持,我们可以调用 OutputStream 的 writeObject 方法来做,如果要让 java 帮我们做,要被传输的对象必须实现 serializable 接口,
这样,javac 编译时就会进行特殊处理,编译的类才可以被 writeObject 方法操作,这就是所谓的序列化。需要被序列化的类必须实现
Serializable 接口,该接口是一个 mini 接口,其中没有需要实现的方法,implements Serializable 只是为了标注该对象是可被序列化的。
例如,在 web 开发中,如果对象被保存在了 Session 中,tomcat 在重启时要把 Session 对象序列化到硬盘,这个对象就必须实现 Serializable 接口。如果对象要经过分布式系统进行网络传输或通过 rmi 等远程调用,这就需要在网络上传输对象,被传输的对象就必须实现
Serializable 接口。

总结:多记多练

以上就是今天要讲的内容,本文仅仅简单介绍了java基础


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值