有关于Java基础的小知识点

简介: 1.String s = "Hello";s = s + " world!";这两行代码执行后,原始的String 对象中的内容到底变了没有?、2.是否可以继承 String 类?、3.String s = new String("xyz");创建了几个 String Object? 二者之间有什么区别?、4.String 和 StringBuffer 的区别、5.try {}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会不会被执行,什么时候被执行,在 return 前还是后?、6.final, finally, finalize 的区别。

1.String s = "Hello";s = s + " world!";这两行代码执行后,原始的
String 对象中的内容到底变了没有?
没有。因为 String 被设计成不可变(immutable)类,所以它的所有对象都是不可变对象。在这段代码中,s 原先指向一个 String 对
象,内容是 "Hello",然后我们对 s 进行了+操作,那么 s 所指向的那个对象是否发生了改变呢?答案是没有。这时,s 不指向原来那个
对象了,而指向了另一个 String 对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用 String
来代表字符串的话会引起很大的内存开销。因为 String 对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个 String
对象来表示。这时,应该考虑使用 StringBuffer 类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。并且,这两种类的
对象转换十分容易。
同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都 new 一个 String。例如我们要在构造器中对一个名叫 s 的 String
引用变量进行初始化,把它设置为初始值,应当这样做:
public class Demo {
private String s;
... public Demo { s = "Initial Value";
}
... }
而非
s = new String("Initial Value");
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为 String 对象不可改变,所以对于内容相同的字
符串,只要一个 String 对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的 String 类型属性 s 都指向同一个对
象。
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java 认为它们代表同一个 String 对象。而用关键字 new 调用构造
器,总是会创建一个新的对象,无论内容是否相同。
至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在开发一
个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因
为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能
会造成性能上的问题。所以 Java 标准类库还提供了一个可变版本,即 StringBuffer。
2.是否可以继承 String 类?
String 类是 final 类故不可以继承。
3.String s = new String("xyz");创建了几个 String Object? 二者之间有什么区
别? xyz 是字面量
两个,一个放在常量区,不管写多少遍,都是同一个。New String 每写一遍,就创建一个新。
4.String 和 StringBuffer 的区别
JAVA 平台提供了两个类:String 和 StringBuffer,它们可以储存和操作字符串,即包含多个字符的字符数据。这个 String 类提供了
数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可以使用StringBuffer。
典型地,你可以使用 StringBuffers 来动态构造字符数据。另外,String 实现了 equals 方法,new String“( abc”).equals(new String“( abc”)
的结果为 true,而 StringBuffer 没有实现 equals 方法,所以,new StringBuffer“( abc”).equals(new StringBuffer“( abc”)的结果为 false。
接着要举一个具体的例子来说明,我们要把 1 到 100 的所有数字拼起来,组成一个串。
StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{ sbf.append(i);
}
上面的代码效率很高,因为只创建了一个 StringBuffer 对象,而下面的代码效率很低,因为创建了 101 个对象。
String str = new String();
for(int i=0;i<100;i++)
{ str = str + i;
}
5.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
6.final, finally, finalize 的区别。
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成 final 类型,例如,一段代码……
finally 是异常处理语句结构的一部分,表示总是执行。
//析构函数
finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回
收,例如关闭文件等。JVM 不保证此方法总被调用
7.运行时异常与一般异常有何异同?
异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误。java 编译器要求方法必须声明抛出可能发生的非运行时异常,但是并不要求必须声明抛出未被捕获的运行时异常。
8.error 和 exception 有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。 exception 表示
一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
9.给我一个你最常见到的 runtime exception。
ArithmeticException, 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
10.sleep() 和 wait() 有什么区别?
sleep 是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会
自动恢复。调用 sleep 不会释放对象锁。 wait 是 Object 类的方法,对此对象调用 wait 方法导致本线程放弃对象锁,进入等待此对象的
等待锁定池,只有针对此对象发出 notify 方法(或 notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。
sleep 就是正在执行的线程主动让出 cpu,cpu 去执行其他线程,在 sleep 指定的时间过后,cpu 才会回到这个线程上继续往下执行,如
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!");
}
}
}
}
11.同步和异步有何异同,在什么情况下分别使用他们?举例说明。
如果数据将在线程间共享。例如正在写的数据以后可能被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那
么这些数据就是共享数据,必须进行同步存取。
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很
多情况下采用异步途径往往更有效率。
果当前线程进入了同步锁,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 方法释放锁。
12.当一个线程进入一个对象的一个 synchronized 方法后,其它线程是否可进入此对
象的其它方法?
分几种情况:
1.其他方法前是否加了 synchronized 关键字,如果没加,则能。
2.如果这个方法内部调用了 wait,则可以进入其他 synchronized 方法。
3.如果其他个方法都加了 synchronized 关键字,并且内部没有调用 wait,则不能。
13.多线程有几种实现方法?同步有几种实现方法?
多线程有两种实现方法,分别是继承 Thread 类与实现 Runnable 接口
同步的实现方面有两种,分别是 synchronized,wait 与 notify wait():使一个线程处于等待状态,并且释放所持有的对象的 lock。
sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉 InterruptedException 异常。
notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由 JVM 确定唤
醒哪个线程,而且不是按优先级。
Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
14.启动一个线程是用 run()还是 start()? . 启动一个线程是调用 start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码,run()方法
是该线程所关联的执行代码。

相关文章
|
26天前
|
安全 Java 编译器
揭秘JAVA深渊:那些让你头大的最晦涩知识点,从泛型迷思到并发陷阱,你敢挑战吗?
【8月更文挑战第22天】Java中的难点常隐藏在其高级特性中,如泛型与类型擦除、并发编程中的内存可见性及指令重排,以及反射与动态代理等。这些特性虽强大却也晦涩,要求开发者深入理解JVM运作机制及计算机底层细节。例如,泛型在编译时检查类型以增强安全性,但在运行时因类型擦除而丢失类型信息,可能导致类型安全问题。并发编程中,内存可见性和指令重排对同步机制提出更高要求,不当处理会导致数据不一致。反射与动态代理虽提供运行时行为定制能力,但也增加了复杂度和性能开销。掌握这些知识需深厚的技术底蕴和实践经验。
45 2
|
2月前
|
存储 算法 安全
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
Java面试题:Java内存模型及相关知识点深度解析,Java虚拟机的内存结构及各部分作用,详解Java的垃圾回收机制,谈谈你对Java内存溢出(OutOfMemoryError)的理解?
45 0
|
3天前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
29天前
|
安全 Java 程序员
阿里开发手册 嵩山版-编程规约 (四)OOP规约-Java程序员必看知识点!!!
《阿里开发手册 嵩山版》的OOP规约部分强调了面向对象编程的最佳实践,包括正确使用静态方法、覆写方法的注解、可变参数的使用、接口的稳定性、equals和compareTo方法的使用、BigDecimal的正确比较、包装类与基本数据类型选择、POJO类的属性和方法设计等,以提升代码的质量和维护性。
|
3月前
|
存储 Java API
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
Java数据结构之ArrayList(如果想知道Java中有关ArrayList的知识点,那么只看这一篇就足够了!)
|
3月前
|
安全 Java
|
3月前
|
设计模式 Java 编译器
Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)
Java中的内部类(如果想知道Java中有关内部类的知识点,那么只看这一篇就足够了!)
|
3月前
|
Java 程序员 编译器
Java 异常处理详解(如果想知道Java中有关异常处理的知识点,那么只看这一篇就足够了!)
Java 异常处理详解(如果想知道Java中有关异常处理的知识点,那么只看这一篇就足够了!)