学习笔记: Java基础+集合+多线程+JVM

本文详细介绍了Java的基础知识,包括Java的特点,如面向对象、继承、封装和多态,以及与C++的区别。深入探讨了Java的主类、输入输出方法、基本数据类型与引用类型的区别,String类的特性,以及多线程和并发编程的相关概念,如线程状态、死锁避免和同步机制。同时,文章还涵盖了JVM的基础,如类加载机制和内存管理。内容丰富,适合Java初学者和进阶者阅读。

目录

Java基础

Java的特点

面向对象和面向过程的区别

  • 面向过程:
    面向过程是一种以过程为中心的编程思想。面向过程的性能比面向对象高,因为类的调用需要实例化,开销大,比如单片机,嵌入式开发等一般都采用面向过程开发。
  • 面向对象:
    因为对象具有封装,继承,多态的特性,所以面向对象易维护,易复用,易扩展,可以设计出低耦合,更灵活和更易维护的系统。

面向对象的特性以及你对这些特性的理解

  1. 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。
  2. 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。
  3. 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调
    用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西。
  4. 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。

注意:默认情况下面向对象有 3 大特性,封装、继承、多态,如果面试官问让说出 4 大特性,那么我们就把抽象加上去

Java语言的特点

  1. 面向对象(封装,继承,多态);
  2. 平台无关性(Java虚拟机实现平台无关性);
  3. 支持多线程(与C++相比,Java语言提供了多线程支持);
  4. 支持网络编程;
  5. 编译与解释并存;
  6. 可靠性;
  7. 安全性;

Java和C++的区别

  • 都是面向对象的语言,都支持封装,继承和多态;
  • Java不提供指针来直接访问内存,程序内存更安全;
  • Java的类是单继承,而C++支持多继承;虽然Java的类不可以多继承,但接口可以多继承;
  • Java有自动内存管理机制,不需要程序员手动释放无用内存;
  • 在C语言中,字符串或者字符数组的最后都会有一个‘\0’来表示结束。但在Java语言中没有结束符这一概念。

什么是Java程序的主类,应用程序和小程序的主类有什么不同?

一个程序中可以有多个类,但只能有一个类是主类。主类是Java程序执行的入口点。在Java应用程序中,这个主类是指包含main()方法的类。而在Java小程序中,这个主类是一个继承来自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。
应用程序是从主线程启动的(即main()方法),而applet小程序中没有main()方法,主要是嵌在浏览器页面上运行(调用init()或者run()来启动),嵌入浏览器这点跟flash的小游戏类似。

import java和javax的区别

JavaAPI所必需的包是java开头的包,javax当时只是扩展API包来使用。随着时间推移,javax逐渐地扩展为Java API的组成部分。但是将javax包移动到java包会消耗大量时间和会破坏一堆现有的代码。最终决定javax包将成为API的一部分。

获取用键盘输入常用的两种方法?

  • 方法一:通过Scanner
 	Scanner input = new Scanner(System.in);
	String str=input.nextLine();
	input.close();
  • 方法二:通过BufferedReader
BufferedReader input=new BufferedReader(new     InputStreamReader(System.in));
String str=input.readLine();//readLine()需要throws IOException
input.close();

基本数据类型和引用类型

自动装箱与拆箱

  • 装箱:将基本类型用它们对应的引用类型包装起来;
  • 拆箱:将包装类型转换为基本数据类型

装箱和拆箱操作发生在引用类型与值类型之间转换。

数据类型之间的转换

(1)字符串如何转基本数据类型?
调用基本数据类型对应的包装类中的方法 parseXXX(String)或 valueOf(String)即可返回相应基本类型。
(2)基本数据类型如何转字符串?
一种方法是将基本数据类型与空字符串(“”)连接(+)即可获得其所对应的字符串;另一种方法是调用 String
类中的 valueOf()方法返回相应字符串。

String类常用方法

是否可以继承String类?

String类是final类,不可以被继承。

String 是基本数据类型吗?

String 是引用类型,底层用 char 数组实现的。

当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?

是值传递。Java 语言的方法调用只支持参数的值传递。

Integer 与 int 的区别

int 是 java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 java为 int 提供的封装类。int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为 0 的区别,int 则无法表达出未赋值的情况。

Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应,例如,ceil 的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为12,Math.ceil(-11.3)的结果是-11;floor 的英文意义是地板,该方法就表示向下取整,Math.floor (11.6)的结果为 11,Math.floor (-11.6)的结果是-12;最难掌握的是 round 方法,它表示“四
舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下取整,所以,Math.round(11.5)
的结果为 12,Math.round(-11.5)的结果为-11。

String 是最基本的数据类型吗?

基本数据类型包括 byte、int、char、long、float、double、boolean 和 short。

java.lang.String 类是 final 类型的,因此不可以继承这个类、不能修改这个类。为了提高效率节省空间,我们应该用 StringBuffer 类

String s = new String(“xyz”);创建了几个 String Object? 二者之间有什么区别?

两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓冲区中的那一个。New String 每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建出一个新 String 对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。

数组有没有 length()这个方法? String 有没有 length()这个方法?

数组没有 length()这个方法,有 length 的属性。String 有 length()这个方法。

下面这条语句一共创建了多少个对象:String s=“a”+“b”+“c”+“d”;

答:对于如下代码:
String s1 = “a”;
String s2 = s1 + “b”;
String s3 = “a” + “b”;
System.out.println(s2 = = “ab”);
System.out.println(s3 = = “ab”);
第一条语句打印的结果为 false,第二条语句打印的结果为 true,这说明 javac 编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。

编译器在编译时优化后,相当于直接定义了一个”abcd”的字符串,所以,
上面的代码应该只创建了一个 String 对象。
String s = “a” + “b” + “c” + “d”;
System.out.println(s == “abcd”);
最终打印的结果应该为 true。

short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?

对于 short s1 = 1; s1 = s1 + 1; 由于 s1+1 运算时会自动提升表达式的类型,所以结果是 int 型,
再赋值给 short 类型 s1 时,编译器将报告需要强制转换类型的错误。
对于 short s1 = 1; s1 += 1;由于 += 是 java 语言规定的运算符,java 编译器会对它进行特殊处
理,因此可以正确编译。

char 型变量中能不能存贮一个中文汉字?为什么?

char 型变量是用来存储 Unicode 编码的字符的,unicode 编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在 unicode 编码字符集中,那么,这个 char 型变量中就不能存储这个特殊汉字。补充说明:unicode 编码占用两个字节,所以,char 类型的变量也是占用两个字节。

String,StringBuffer和StringBuilder的区别是什么?String为什么是不可变的?

简单来说,String类中使用final关键字修饰字符数组来保存字符串的,private final char value[ ],所以String对象是不可变的。

而StringBuffer和StringBuilder都继承自AbstractStringBuilder类,在AbstactStringBuilder中也是使用字符数组来保存字符串char[ ] value,但是没有用final关键字修饰,所以这两种对象是可变的。

线程安全性

String中的对象是不可变的,可以理解为常量,是线程安全的。而AbstractStringBuilder是StringBuilder和StringBuffer的公共父类,定义了一些字符串的基本操作,如expandCapacity,append,insert,indexOf等公共方法。StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。但StringBuilder没有对这些添加同步锁,所以是线程不安全的。

性能

每次对String类型进行改变时,都会生成一个新的String对象,然后将指针指向新的String对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象的引用。相同情况下,使用StringBuilder相比StringBuffer仅能获得10%~15%的性能提升,但却要冒多线程不安全的风险。

应用情景
1. 操作少量的数据:适用String
2. 单线程操作字符串缓冲区下操作大量数据:适用StringBuilder
3. 多线程操作字符串缓冲区下操作大量数据:适用StringBuffer

  • StringBuffer类对象创建之后可以再修改和变动,String类不可以。

字符型常量和字符串常量的区别

  • 形式上:字符常量是单引号引起的一个字符;而字符串常量是双引号引起的若干个字符
  • 含义上:字符常量相当于一个整型值(ASCII值),可以参加表达式运算;字符串常量代表一个地址值(该字符串在内存中存放的位置)
  • 占用内存大小:字符常量只占用2个字节,而字符串常量占若干个字节。(注意:char在Java中占2个字节)

用最有效率的方法算出 2 乘以 8 等於几?

2 << 3,
因为将一个数左移 n 位,就相当于乘以了 2 的 n 次方,那么,一个数乘以 8 只要将其左移 3位即可,而位运算 cpu 直接支持的,效率最高,所以,2 乘以 8 等於几的最效率的方法是 2 << 3。

==和equals的区别

  • == : 基本数据类型判断的是值,引用数据类型判断是内存地址。
  • equals():字符串比较的是内容,而对象是判断两个对象是否相等。有两种使用情况:
    1. 类没有覆盖equals()方法,则通过equals()比较该类的两个对象,等价于通过==比较两个对象;
    2. 类覆盖了equals()方法。比较的是两个对象的内容是否一致。

一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

可以有多个类,但只能有一个 public 的类,并且 public 的类名必须与文件名相一致。

循环结构

在 Java 中,如何跳出当前的多重嵌套循环

在最外层循环前加一个标记如 A,然后用 break A;可以跳出多重循环。
在这里插入图片描述

break 和 continue 的区别?

break 和 continue 都是用来控制循环的语句。
break 用于完全结束一个循环,跳出循环体执行循环后面的语句。
continue 用于跳过本次循环,执行下次循环。

说说&和&&的区别。

&和&&都可以用作逻辑与的运算符,表示and,当运算符两边的表达式结果都为true时,整个运算结果才为true,否则,只要一边为false,则结果为false。

此外,&&还具有短路功能,当第一个表达式为false时,不会去计算第二个表达式。例如:if( i==1&&result++>0)第一个表达式为false时,result不会去计算自增操作。

&还可以用作位运算符,当&操作符两边的表达式不是 boolean 类型时,&表示按位与操作,
我们通常使用 0x0f 来与一个整数进行&运算,来获取该整数的最低 4 个 bit 位,例如,0x31 & 0x0f的结果为 0x01。

switch 语句能否作用在 byte 上,能否作用在 long 上,能否作用在 String 上?

在 switch(expr1)中,expr1 只能是一个整数表达式或者枚举常量(更大字体),整数表达式可以是 int 基本类型或 Integer 包装类型,由于,byte,short,char 都可以隐含转换为 int,所以,这些类型以及这些类型的包装类型也是可以的。显然,long 和 String 类型都不符合 switch 的语法规定,并且不能被隐式转换成 int 类型,所以,它们不能作用于 swtich 语句中。

继承与多态

Java 中实现多态的机制是什么?

靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动
态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变
量的类型中定义的方法。

修饰符

修饰符可以分为访问修饰符和非访问修饰符

访问权限修饰符

  • public:共有访问。对所有的类都可见。
  • protected:保护型访问。对同一个包可见,对不同包的子类也可见。
  • default:默认访问权限。只对同一个包可见,但对不同包的子类不可见。
  • private:私有访问。只对同一个类可见,其余都不可见
修饰符 同类 同包 子类 其他包
public
protected
default
private

非访问权限修饰符

  • static:用来修饰类静态方法或静态变量。
  • final:主要用来修饰类,方法和变量。final修饰的类不可继承,修饰的方法不能被继承和重新定义,修饰的变量称为常量,是不可改变的。(即final修饰,属性不可变,方法不可重写,类不可继承)
  • abstract:用来创建抽象类或抽象方法。
  • synchronized:用来进行多线程的同步。用来给对象加锁,最多一个线程执行。
  • volatile:修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值,而且,当成员变量发生变化时,会强制线程将变化的值写回到共享内存中。这样在任何时刻,两个不同线程总是看到某个成员变量的同一个值,每次更新对其他线程都是立即可见的,对volatile修饰的变量的操作时不会造成阻塞的,保证了其他线程的立即可见性,没有保证原子性,不可用于多线程下的计数器。
  • transient:修饰不需要进行序列化的属性。
  • serialize:Java对象序列化为二进制文件。
  • finalize:设计的目的是保证对象在被GC完毕完成特定的资源回收。

保留字、关键字、修饰符

Java 有没有 goto?

java 中的保留字,现在没有在 java 中使用。

使用 final 关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用 final 关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容
还是可以改变的。例如,对于如下语句:
final StringBuffer a=new StringBuffer(“immutable”);
执行如下语句将报告编译期错误:
a=new StringBuffer("");
但是,执行如下语句则可以通过编译:
a.append(" broken!");

final, finally, finalize 的区别。

final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成 final 类型,例如,一段代码……
finally 是异常处理语句结构的一部分,表示总是执行。
finalize 是 Object 类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可
以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM 不保证此方法总被
调用。

Java序列化中如何不让某些字段进行序列化?

对不想进行序列化的变量使用transient关键字修饰。
transient关键字的作用是:阻止实例中那些用此关键字修饰的变量序列化;当对象被反序列化时,被transient修饰的变量值也不会被持久化和恢复。transient只能修饰变量,不能修饰类和方法。

重写与重载

重载和重写的区别

重载:发生在同一个类中,方法名必须相同,但是参数类型、参数个数、参数顺序、方法返回值和访问修饰符可以不用 。

重写:发生在子类对父类的允许访问的方法的实现过程进行重新编写,发生在子类中。其中,方法名,参数列表必须相同,且返回值范围,抛出的异常范围必须小于或等于父类,访问修饰符范围必须大于或等于父类。

构造器Constructor是否可被override重写

Constructor不能被override(重写),但是可以被overload(重载),所以一个类中可以有多个构造方法。

为什么函数不能根据返回类型来区分重载?

因为返回值不同,而方法名相同,当调用该两个方法时,编译器是不知道你要调用哪个函数,且函数的返回值只是作为函数运行之后的一个状态,它是保持方法的调用者与被调用者进行通信的关键,而并不能作为某个方法的标识。

抽象类与接口

接口和抽象类的区别

  1. 一个子类只能继承一个抽象类,但能实现多个接口;
  2. 抽象类可以有构造方法,接口没有构造方法;
  3. 抽象类和接口都允许定义成员,但接口的成员必须是常量;
  4. 抽象类可以有普通成员变量,接口没有普通成员变量;
  5. 抽象类和接口都可以有静态成员变量(但抽象类中的静态成员变量的访问类型是任意的,接口只能是public static final 默认)
  6. 抽象类可以没有抽象方法,也可以有普通方法。而接口中都是抽象方法
  7. 抽象类可以有静态方法,接口不能有静态方法;
  8. 抽象类中的方法访问权限修饰符是public或protected,而接口只能有public;
  9. 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范;
备注:
	1. 在JDK8中,接口也可以定义静态方法,可以直接使用接口名调用。实现类和实现是不可以调用的。如果出现相同的方法,必须重写,否则报错。
	2. JDK9的接口被允许定义私有方法

总结:
	jdk7及之前的版本中,接口中只能有常量和抽象方法。这些接口方法必须由选择实现接口的类实现;
	jdk8中,接口可以有默认方法和静态方法;
	jdk9中,接口引入了私有方法和私有静态方法;

抽象的(abstract)方法是否可同时是静态的(static), 是否可同时是本地方法(native),是否可同时被 synchronized

都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由
本地代码(如 C 代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized 和方法的实现细节有关,
抽象方法不涉及实现细节,因此也是相互矛盾的。

"=="和 equals 方法究竟有什么区别?

" = = “操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存
储的数值是否相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用” = = "操作符。而equals通常用于比较字符串的内容是否相等。

静态与实例

静态方法和实例方法有什么不同

  1. 在外部调用静态方法时,可是使用“ 类名.方法名 ”的方式,也可以使用 “ 对象名.方法名”的方式。而实例方法只能通过后者调用方法,也就是说,静态方法无需创建对象;
  2. 静态方法在访问本类的成员变量时,只允许访问静态变量(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。

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

  • 语法上,静态变量需要static修饰,而实例对象不需要修饰符。
  • 运行时的区别,静态变量无序实例化对象,通常使用“类名+变量名”来使用,或者“对象名+变量名”来使用,而实例变量需要对对象进行实例化才可以被调用。

是否可以从一个 static 方法内部发出对非 static 方法的调用?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值