1、Java学习手册:Java基础知识点
2、Java学习手册:Java面向对象面试问题
3、Java学习手册:Java集合、泛型面试问题
4、Java学习手册:Java并发与多线程面试问题
5、Java学习手册:Java虚拟机面试问题
6、Java学习手册:Java IO面试问题
7、Java学习手册:Java反射机制面试问题
8、Java学习手册:Java网络编程面试问题
9、Java学习手册:Java异常面试问题
10、Java学习手册:Java设计模式面试问题
11、Java学习手册:Java数据库面试问题
不同点 | Java | C++ |
---|---|---|
1 | Java为编译型-解释型语言(程序源代码通过Java编译器编译成字节码,然后由JVM解释执行) | C++为编译型语言(源代码经过编译和链接后生成可执行的二进制代码) |
2 | Java执行速度比C++慢,Java能够跨平台执行 | C++不能跨平台执行 |
3 | Java为纯面向对象语言,所有代码都必须在类中实现,除基本数据类型外,所有类型都是类 | - |
4 | Java语言中不存在全局变量或全局函数(1、全局变量破坏了引用的透明性;2、全局变量制造了命名空间冲突;) | C++兼具面向过程和面向对象编程的特点,可以定义全局变量和全局函数 |
5 | Java没有指针概念,有效防止C++语言操作指针可能引起的系统问题 | C++有指针的概念 |
6 | Java语言不支持多重继承,但是Java语言引入了接口的概念,可以同时实现多个接口 | C++支持多重继承 |
7 | Java语言提供了垃圾回收器来实现垃圾的自动回收,不需要程序显式的管理内存的分配 | C++需要开发人员去管理对内存的分配 |
8 | Java语言没有析构函数,但引入了finalize()方法 | C++语言会把释放资源的代码放到析构函数中 |
9 | Java不支持运算符重载 | C++语言支持运算符重载 |
10 | Java语言没有预处理器,但提供import机制与C++预处理器功能类似 | C++语言支持预处理 |
11 | Java不支持默认函数参数 | C++支持默认函数参数 |
12 | Java不支持goto语句(Java中goto是保留关键字) | C++支持goto语句 |
13 | Java不支持自动强制类型转换,必须由开发人员显式地强制类型转换 | C++支持自动强制类型转换 |
14 | Java不包含结构和联合,所有内容都封装在类里面 | C++中,结构和联合的所有成员均为公有,往往会导致安全性问题 |
15 | Java具有平台无关性,即对每种数据类型都分配固定长度 | C++中同一个数据类型在不同的平台上会分配不同的字节数 |
16 | Java提供对注释文档的内建支持 | - |
17 | Java提供了一些标准库,用于完成特定任务 | C++则依靠一些非标准的、其他厂商提供的库 |
1、Java学习手册:日期操作
2、Java学习手册:正则表式
3、Java学习手册:Java中复制数组的方法
4、Java学习手册:String&StringBuffer&StringBuilder&StringTokenizer
5、Java学习手册:实例化String对象
6、Java学习手册:finally块中的代码什么时候被执行?
7、Java学习手册:final&finally&finalize
8、Java学习手册:assert
9、Java学习手册:volatile
10、Java学习手册:instanceof
11、Java学习手册:strictfp
12、Java学习手册:static
13、Java学习手册:this&super
14、Java学习手册:数组的初始化方式
15、Java学习手册:如何获取父类的类名?
16、Java学习手册:length属性&lengh()方法
17、Java学习手册:Java中数组是不是对象
18、Java学习手册:无符号左移&无符号右移&有符号右移
19、Java学习手册:break&continue&return
20、Java学习手册:长路逻辑&短路逻辑
21、Java学习手册:运算符优先级
22、Java学习手册:Java基本类型转换
23、Java学习手册:Java程序初始化的顺序
24、Java学习手册:“==”&equals&hashCode
25、Java学习手册:File类
26、Java学习手册:值传递&引用传递
27、Java学习手册:内存泄漏
28、Java学习手册:Java是否支持多继承?为什么?
29、Java学习手册:ArrayList&LinkedList&Vector
30、Java学习手册:堆内存&栈内存&方法区
31、Java学习手册:Collection&Collections
32、Java学习手册:Java锁的分类和特点
33、Java学习手册:死锁
34、Java学习手册:JVM加载class文件的原理机制
35、Java学习手册:垃圾回收(GC)
36、Java学习手册:HashMap&HashTable&TreeMap&WeakHashMap
37、Java学习手册:RandomAccessFile
38、Java学习手册:Java序列化
39、Java学习手册:TCP与UDP
40、Java学习手册:Java Socket
41、Java学习手册:Java NIO
42、Java学习手册:XML
43、Java学习手册:异常处理的原理
44、Java学习手册:Error(错误类)&Exception(异常类)
45、Java学习手册:运行时异常&检查异常
46、Java学习手册:数据库原理
47、Java学习手册:JDBC中getString()方法与getObject()方法有什么区别?
48、Java学习手册:JDBC中Class.forName的作用是什么?
49、Java学习手册:如何通过JDBC访问数据库?
50、Java学习手册:JDBC中Statement&PreparedStatement&CallableStatement
51、Java学习手册:遍历Map的五种方法
52、Java学习手册:clone方法(浅复制&深复制)
53、Java学习手册:向上造型
54、Java学习手册:不可变类
55、Java学习手册:内部类
56、Java学习手册:抽象类&接口
57、Java学习手册:多态的实现机制(重载和覆盖)
58、Java学习手册:组合&继承
59、Java学习手册:泛型
60、Java学习手册:迭代器(Iterator)
61、Java学习手册:单例模式——写出一个线程安全的单例类
62、未完待续。。。
(1)编译性语言:只须编译一次就可以把源代码编译成机器语言,后面的执行无须重新编译,直接使用之前编译结果就可以,执行效率较高。代表语言:C、C++、Pascal等。
(2)解释性语言:源代码不能直接翻译成机器语言,而是先翻译成中间代码,再由解释器对中间代码进行解释运行。代表语言:Python、JavaScript、Shell、Ruby、MATLAB等。
Java程序中一句连续的字符串不能分开在两行书写。如果为了方便阅读,想将一个太长的字符串分在两行书写,可以先将这个字符串分为两个字符串,然后用加号(+)将这两个字符串连起来,在加号(+)处断行。
System.out.println("这是第一个"+
"Java程序");
文档注释是以/*开头,并在注释内容末尾以/结束。文档注释是一段代码概括性的解释说明,可以使用javadoc命令将文档注释提取出来生成帮助文档。
(1)包名所有字母一律小写。
(2)类名和接口名每个单词的首字母要大写。
(3)常量名所有字母都大写,单词之间用下划线连接。
(4)变量名和方法名的第一个单词首字母小写,从第2个单词开始,每个单词首字母大写。(驼峰命名法)
在进行取模(%)运算时,运算结果的正负取决于被取模(%左边的数)的符号,与模数(%右边的数)无关。
例:(-5) % 3 = -2, 5 % (-3) = 2
Java学习手册:static
(1)由static修饰的变量称为静态变量,也称类变量。
(2)静态变量定义位置在所有方法之外。
(3)静态变量与静态方法都是在类从磁盘加载至内存后被创建,与类同时存在,同时消亡。
(4)静态变量又称类的成员变量,在类中是全局变量,可以被类中的所有方法调用。(注:Java中不存在全局变量)
(5)静态变量的值由JVM自动初始化
整型→0,布尔型→false,浮点型→0.0,字符串型→null,字符型→Unicode编码为0的字符(该字符不可见)
static关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错。
在一个静态方法中只能访问static修饰的成员,原因在于没有被static修饰的成员需要先创建对象才能访问,而静态方法在调用时可以不创建任何对象。
JRE(Java运行环境):为Java运行提供运行时环境,包括JVM和Java系统类库。
JDK(Java开发工具包):JDK除了包含JRE之外,还包含开发Java程序所需要的一些命令、工具。
运行一个Java程序所需的最小环境为JRE,开发一个Java程序所需的最小环境为JDK。
public class StringDemo{
public static void main(String[] args){
String s1 = "Hello";
String s2 = s1 + "World!";
System.out.println(s2);
}
}
//程序输出结果如下:
Hello World!
对于上述程序进行内存分析:
注:String为什么要设计成不可变类?
(1)字符串池的需求
字符串池是方法区(Method Area)中的一块特殊的存储区域。当一个字符串已经被创建并且该字符串在池中,该字符串的引用会立即返回给变量,而不是重新创建一个字符串再将引用返回给变量。如果字符串不是不可变的,那么改变一个引用(如: string2)的字符串将会导致另一个引用(如: string1)出现脏数据。
(2)允许字符串缓存哈希码
在java中常常会用到字符串的哈希码,例如: HashMap 。String的不变性保证哈希码始终一,因此,他可以不用担心变化的出现。这种方法意味着不必每次使用时都重新计算一次哈希码——这样,效率会高很多。
(3)安全
String广泛的用于java 类中的参数,如:网络连接(Network connetion),打开文件(opening files )等等。如果String不是不可变的,网络连接、文件将会被改变——这将会导致一系列的安全威胁。操作的方法本以为连接上了一台机器,但实际上却不是。由于反射中的参数都是字符串,同样,也会引起一系列的安全问题。
算术运算时,整个结果为最大类型。
正数溢出变为负,负数溢出变为正。
(1)int类型范围不够,可使用long型。
(2)如果要表示long直接量,需要以L或l结尾。
int d = 10000000000;//编译错误,因为整数直接量超过整数范围
//10000000000这个数值写出来就是错误的,因为Java认为所有直接写出的整型都是int类型,而这个数值超过了int的表达范围
//直接量(literal):就是直接写出来的数,整数的直接量默认为int类型。
long d = 10000000000;//错误
long d = 10000000000L;//正确
(1)double常用于浮点数
(2)double无法精确表示1/10,会出现舍入误差
double b1 = 6;
double b2 = 5.9;
System.out.println(b1-b2);
//输出结果如下:
0.099...964
(3)小数的直接量为double类型
(4)float类型表示需加“f”或“F”
(1)char为字符类型,用于存储单个字符,‘a’,‘王’,‘克’
(2)char采用Unicode字符编码,实际存储的是字符所对应的编码(16位整数)
char ch = 'a';
System.out.println(ch);//赋值为字符
//程序输出结果为:a
char ch1 = 97;//赋值为整数
System.out.println(ch1);
//程序输出结果为:a
char ch2 = '97';//错误,两个字符
(3)字符的直接量放在单引号中’ ’
(4)‘a’→97,‘A’→65,‘0’→48,’\n’表示回车,’\r’表示换行符
(5)转义字符:将特殊字符非特殊化,’\‘表示(\),’\“'表示(")
(1)boolean只能取值true或false(默认false)
(2)boolean一般用于存储关系运算的结果,常用于条件控制
(3)在Java中,布尔值和整数不能相互转换
问题:boolean类型占据多少字节?
答案:作为数组中某元素时,boolean类型占据1个字节(8bit);作为单个变量存储数据时,boolean类型占据4个字节(32bit)。
在使用+=,-=,*=,/=,%=运算符进行赋值时,强制类型转换会自动完成,程序不需要做任何显示的声明。
(关于强制类型转换,详见)
注意:与例5的取模(%)运算略有差别,原因是:取模运算(“Modulo Operation”)和取余运算(“Complementation ”)两个概念有重叠的部分但又不完全一致。主要的区别在于对负整数进行除法运算时操作不同。
在JDK7.0中,switch语句的表达式增加了对字符串类型的支持。在switch(expr1)中,expr1只能是一个整数表达式或者枚举常量,整数表达式可以是int基本类型或Integer包装类型,由于byte、short、char都可以转换为int,所以,这些类型以及这些类型的包装类也是可以的。
switch(整型表达式){
case (int/char类型):
语句1;
语句2;
break;
}
do{
语句块;
}while(boolean表达式);
//1、先执行语句块
//2、再计算boolean表达式的值,若为true,再次执行语句块,知道boolean值为false为止
//3、无论boolean表达式是否为true,都先执行一次语句块
注意:while(boolean表达式);最后面的分号一定要有!!!
Java学习手册:值传递&引用传递
Java在处理基本数据类型(例如int、char、double等)时,都是采用按值传递(传递的是输入参数的复制)的方式执行,除此之外的其他类型都是按引用传递(传递的是对象的一个引用)的方式执行。
(1)对象就是传引用。
(2)原始类型就是传值。
(3)String,Integer,Double等immutable类型因为没有提供自身修改的函数,每次操作都是新生产一个对象,所以要特殊对待。可以认为是传值。
浅复制(Shallow Clone):被复制对象的所有变量都含有与原来对象相同的值,而所有对其他对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。
深复制(Deep Clone):被复制对象的所有变量都含有与原来对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制的新对象。而不再是原有的那些被引用的对象。换言之,深复制把复制的对象所引用的对象都复制了一遍。
以下例所示:
class Test{
public int i;
public StringBuffer s;
}
①三个表达式都可以省略,但分号不能省略,示例:for( ;;),表示死循环。
②表达式1、3可用逗号形式(当多条语句时),但2不可以,表达式2中不能有“,”(逗号),若有多个条件,可用(&&)或(||)连接。
基本类型数组创建后,元素是有默认值的:byte、short、int、long、char为0,而float和double为0.0,boolean默认值为false。
数组new之后,元素也有默认值。引用数组创建后,其元素的默认值为null,不创建元素对象。
JDK提供了Arrays.sort()方法封装了数组的排序算法。Arrays.sort()用的是快速排序,实质是双基准快速排序算法。
package com.haobi;
import java.util.Arrays;
/*
* Arrays.sort()的使用
*/
public class Test {
public static void main(String[] args) {
int[] arr = {49,45,65,21,37};
Arrays.sort(arr);
for(int i=0;i<arr.length;i++) {
if(i == arr.length-1) {
System.out.print(arr[i]);
}else {
System.out.print(arr[i] + " ");
}
}
}
}
//程序输出结果如下:
21 37 45 49 65
//1、将数字转换为字符串
int num = 5;
String s = String.valueOf(num);
//结果:s="5";
//2、将字符串转换为数字
String s = "55";
int num = Integer.parseInt(s);
//结果:num=55;
补充:String类型转换为Char
匿名对象就是没有名字的对象,如果程序中只是用一次该对象,就可以使用匿名对象的方式。
package com.haobi;
/*
* 匿名对象
*/
class Student{
public void tell() {
System.out.println("Hello");
}
}
public class Test1 {
public static void main(String[] args) {
new Student().tell();
}
}
//程序输出结果如下:
Hello
①引用类型变量可以存储该类对象的地址信息,通常称为“指向该类的对象”,当一个引用类型变量指向该类的对象就可以通过这个变量对对象实施访问。
②除8种基本类型外,用类名、接口、数组等声明的变量都称为“引用类型变量”,简称引用变量。
当创建了引用类型的变量之后,就可以通过引用来访问对象的成员变量或调用方法。
(1)引用类型之间画等号:指向同一个对象,对其中一个修改,会影响到另一个。
(2)基本类型之间画等号:赋值,对其中一个修改,不会影响到另外一个。
(关于堆空间、栈空间、方法区,详见)
Null:空,意为不再指向任何对象。
NullPointerException:当一个引用的值为Null的时候,如果通过引用访问对象成员变量或者调用方法是不合逻辑的,会产生NullPointerException。
方法的签名包括方法名和参数列表。(方法名+参数列表)
注:一个类中不能出现两个方法签名一样的方法。参数列表只看类型,与参数名无关。
主要用于为类中的属性初始化操作。
①常常用于给成员变量赋初值
②与类同名,没有返回值类型,也不写void
③在创建对象时被自动调用
④若自己不写构造,则编译器默认提供一个无参构造;若自己写了构造,则编译器不再默认提供。
⑤构造方法可以重载(构造常常需要重载),一个构造方法可以通过this关键字,方可调用另一个重载的构造方法
在一个类中定义的方法如果同时满足了以下3个条件,该方法称为构造方法。具体如下:
①方法名与类名相同
②在方法名的前面没有返回值类型的声明
③在方法中不能使用return语句返回一个值,但是可以单独写return语句作为方法的结束
package com.haobi;
import java.math.BigInteger;
/*
* BigInteger:可以让超过Integer范围内的数进行运算
*/
public class Test1 {
public static void main(String[] args) {
BigInteger b1 = new BigInteger("111111111111111111111111111111");
BigInteger b2 = new BigInteger("222222222222222222222222222222");
System.out.println("加法:"+b1.add(b2));//+
System.out.println("减法:"+b2.subtract(b1));//-
System.out.println("乘法:"+b1.multiply(b2));//*
System.out.println("除法:"+b2.divide(b1));//除
BigInteger[] arr = b1.divideAndRemainder(b2);
System.out.println("取除数:"+arr[0]);
System.out.println("取余:"+arr[1]);
}
}
//程序输出结果如下:
加法:333333333333333333333333333333
减法:111111111111111111111111111111
乘法:24691358024691358024691358024641975308641975308641975308642
除法:2
取除数:0
取余:111111111111111111111111111111
如果想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象的具体语法格式如下:
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
方法一:通过Scanner
import java.util.Scanner;
public class Test5 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
System.out.println(s);
sc.close();
}
}
方法二:通过BufferedReader
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test6 {
public static void main(String[] args) {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = null;
try {
s = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println(s);
}
}
- | 成员变量 | 局部变量 |
---|---|---|
类中位置 | 类中方法外 | 在方法定义中或者方法声明上 |
内存中位置 | 在堆内存 | 在栈内存 |
生命周期 | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕而消失 |
初始化值 | 有默认值初始化 | 没有默认值初始化,必须定义、赋值,然后才能使用 |
访问范围 | Private | Default | Protected | Public |
---|---|---|---|---|
同一类中 | ✔ | ✔ | ✔ | ✔ |
同一包中 | - | ✔ | ✔ | ✔ |
子类中 | - | - | ✔ | ✔ |
全局范围 | - | - | - | ✔ |
类的访问修饰只有2种。对于类,只能用public或默认方式修饰。(1)public修饰的类可被任一类使用;(2)默认访问控制的类只可以被同一个包中的类使用;
类成员的访问修饰:4种都可以。
提供了一种命名机制,用于管理类名空间:
①避免类的命名冲突
②包名可以有层次结构,建议所有字母小写
③完全限定名:包名.类名
④同包类不能同名
主要有以下两个作用:①提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package中的类可以存在相同的名字;②对类按功能进行分类,使项目的组织更加清晰;
①同包中的类可以直接访问
②不同包中的类:(1)import声明类,再直接访问(2)完全限定名:包名.类名
(1)对象向上转型
父类 父类对象 = 子类实例 (程序自动完成)
(2)对象向下转型
子类 子类对象 = (子类)父类实例 (强制类型转换)
如果把0-65535范围内的一个int类型数直接量赋给char类型变量,系统会自动把这个int类型整数当成char类型来处理。
char ascii = 98;//等价于 char ascii = 'b';
System.out.println(ascii);
//程序输出结果如下:
b
//系统会将‘98’认定为两个字符,而char用于存储单个字符
char ascii = '98';//出错
“+”有两种运算规则,一种是两端为数字则为数学加法运算,另一种是实现字符串连接,也可以实现字符串与其他数据类型的相连。
Math.round(double s)用于实现对浮点数值进行四舍五入的计算,返回long类型的整型数据。
当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前执行。
子类构造器调用父类构造器分为如下几种情况:(A、B、C)
A、子类构造器执行体的第一行使用super显示调用父类构造器,系统将根据super调用里传入的实参列表调用父类对应的构造器。
B、子类构造器执行的第一行代码使用this显式调用本类中重载的构造器,系统将根据this调用里传入的实参列表调用父类对应的构造器。
C、子类构造器执行体中既没有super调用,也没有this调用,系统将会在执行子类构造器之前,隐式调用父类无参数的构造器。
子类的构造方法中必须通过super关键字调用父类的构造方法,这样可以妥善的初始化继承自父类的成员变量。如果子类的构造方法中没有调用父类的构造方法,Java编译器会自动加入对父类无参构造方法的调用。(如果父类没有无参构造方法,会有编译错误。)
java.lang.string使用了final修饰,不能被继承。(String是不可变对象:字符串创建后,内容不可改变)
字符串底层封装了字符数组及针对字符数组的操作算法。
字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值。
Java字符串在内存中采用Unicode编码方式,任何一个字符(算一个字符长度)对应两个字节的定长编码。
String常量值:静态字符串在常量池中创建,并尽量使用同一对象,重用静态字符串。对于重复出现的字符串直接量,JVM会首先在常量池中查找,如果存在即返回对象。
若要修改String,则会创建新的对象。
(1)单独使用“ ”引号创建的字符串都是常量,编译期就已经确定存储到String Pool中。
(2)使用new String(" ")创建的对象会存储到heap(堆)中,是运行期新创建的。
(3)使用只包含常量的字符串连接符如“aa”+"aa"创建的也是常量,编译期就已经确定存储到String Pool中。
(4)使用包含变量的字符串连接符“aa”+s1创建的对象是运行期间才创建的,存储在heap中。
Java语言中很多地方会默认调用对象的toString方法:
——字符串对象,自动调用对象的toString方法
——System.out.println(任意对象),直接调用toString方法
如果不重写toString方法,将使用Object类的toString方法,其逻辑为:
类名@散列码
//String重写toString就是将自身返回了
public String toString(){
return this;
}
在进行类型转换的范畴内,有一种特殊的转换,需要将int这样的基本数据类型转换为对象。
所有基本类型都有一个与之对应的类,即包装类。
包装类用于解决基本类型不能参与面向对象开发:①包装类中封装了一些很实用的方法和常量;②包装类在集合中用来定义集合元素的类型;
包装类是不可变类,在构造了包装类对象后,不允许更改包装类在其中的值。
包装类是final的,不能定义它们的子类。
基本类型 | 包装类 | 父类 |
---|---|---|
int | java.lang.Integer | java.lang.Number |
long | java.lang.Long | java.lang.Number |
double | java.lang.Double | java.lang.Number |
short | java.lang.Short | java.lang.Number |
float | java.lang.Float | java.lang.Number |
byte | java.lang.Byte | java.lang.Number |
char | java.lang.Character | java.lang.Object |
boolean | java.lang.Boolean | java.lang.Object |
6个数字类型的包装类都有两个常量:MAX_VALUE获取基本类型最大值;MIN_VALUE获取基本类型最小值。
Number的子类必须提供将表示的数值转换为byte、double、float、int、long和short方法:
——doubleValue():以double形式返回指定的数值
——intValue():以int形式返回指定的数值
Integer常用的功能:Integer的静态方法parseInt用于将字符串转换为int。
String str = "123";
int i = Integer.parseInt(str);//123
包装类都支持一个静态方法,允许将字符串转换为对应的基本数据结构,前提是,该字符串必须正确描述该基本类型可以保存的值。若不能准确描述则会抛出异常。
==对于基本数据类型来说,用于比较两个值是否相同;对于引用数据类型来说,用于比较两个对象的内存地址是否相同。
equals方法是Object类中的方法,该方法内部默认使用= =比较两个对象(没有重写equals()方法),Object类的子类可以通过重写equals()方法来定义自己的比较规则,从而达到比较对象值(对象内容)的目的,例如String类重写equals方法后,就可以通过该方法比较两个字符串值是否相等。
当一个字符串与一个字面量进行比较时,应当使用:字面量.equals(变量),这样可以避免空指针的发生。
增强for循环,又叫做新循环。
for(元素类型 e : 集合或数组){
循环体
}
例如:
for(String str : array){
//循环体
}
该循环不能替代传统for循环的工作,其只为了遍历集合或数组,不能对其中元素进行修改。
新循环是编译器认可,Java虚拟机不认可。
新循环在遍历集合的过程中就是迭代器,所以不能通过集合的方法删除元素。
Java学习手册:遍历Map的五种方法(更新于2019/8/19)
当我们要执行程序时,首先操作系统会启动一个进程来运行JVM,JVM启动后会启动一个线程来执行main方法。
当一个进程中的所有前台线程都结束了,进程就结束了。所以并不是说main方法执行完毕进程一定结束。(main方法只是其中一个线程)
(1)replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换。(CharSequence即字符串序列的意思,说白了也就是字符串)
(2)replaceAll的参数是regex,即基于规则表达式的替换,比如:可以通过replaceAll("\d", “*”)把一个字符串所有的数字字符都换成星号。
(3)相同点:都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串。
(4)不同点:replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\d", ""),而replace则不会,replace("\d","")就是替换"\d"的字符串,而不会解析为正则。
注意:
(1)“\”在java中是一个转义字符,所以需要用两个代表一个。
(2)如果只想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串。
答:虽然每个类中都可以定义main()方法,但是只有与文件名相同的用public修饰的类中的main()方法才能作为整个程序的入口方法。
在Java中,由于静态块在类被加载时就会被调用,因此可以在main()方法执行前,利用静态块提前输出信息。
在Java语言中,作用域是由花括号的位置决定的,它决定了其定义的变量名的可见性与生命周期。
一个Java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名与文件名必须相同,若这个文件中没有public的类,则文件名随便是一个类的名字即可。
在一个文件中只能存在一个public class XXX{}
在Java语言中,有些接口内部没有声明任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被叫做标识接口。标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表示实现它的类属于一个特定的类型。
这两个方法都是Object类中定义的方法,所有Java中所有对象都拥有这两个方法。
两个对象的hashcode方法返回值相同,但是equals方法比较结果不一定返回true。
但是两个对象的equals方法返回值为true,这两个对象的hashcode值一定相同,HashSet类使用这种机制来保证集合中没有重复的元素。
在装箱的时候自动调用的是Integer的valueOf(int)方法,而在拆箱的时候自动调用的是Integer的intValue()方法。
在通过valueOf()方法创建Integer对象的时候,如果数值在[-128,127]之间,便返回指向IntegerCache.cache中已经存在的对象的引用;否则创建一个新的Integer对象。
(1)正常情况
package com.haobi;
public class Test1 {
public static void main(String[] args) {
Integer a1 = 200;
Integer b1 = 200;
if(a1==b1) {
System.out.println("equals");
}else {
System.out.println("not equals");
}
Integer a2 = -101;
Integer b2 = -101;
if(a2==b2) {
System.out.println("equals");
}else {
System.out.println("not equals");
}
}
}
//程序输出如下:
not equals
equals
(2)特殊情况
package com.haobi;
public class Aaa {
public static void main(String[] args) {
Integer i1 = new Integer(100);
Integer i2 = new Integer(100);
System.out.println(i1 == i2);
System.out.println(i1.equals(i2));
}
}
//程序输出如下:
false
true
解释:Integer包装类型常量cache为-128到127之间,所以i1和i2是两个对象,= =如果比较的是基本类型,是对基本类型的值进行比较;而如果比较的是引用类型,则是对引用对象在内存中存放的地址进行比较。本程序中,i1和i2均是引用类型,比较的是两个对象的地址,所以是false。而equals比较两个对象的引用是否相等,!!!但是!!!更准确的说,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;但String、Integer包装类和Date等类对equals方法进行了重写,比较的是所指向对象的内容。String类对equals方法进行了重写,用来比较指向字符串对象所存储的字符串是否相等。Integer的equals方法会先判断实例是否是Integer类型,再判断数值是否相等。Double,Float等包装类的equals方法也是如此。
(1)volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
(2)volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
(3)volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
(4)volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
(5)volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。
元注解的作用就是负责注解其他注解。java5.0的时候,定义了4个标准的meta-annotation类型,它们用来提供对其他注解的类型作说明。
(1)@Target
(2)@Retention
(3)@Documented
(4)@Inherited
实例变量对于每个类的实例(对象)来说,都拥有自己的一份,每个对象可以有不同的实例变量值。
但是静态变量对于类以及类的所有对象来说只有一份,所有对象的静态变量值是相同的。
不能被继承,因为这两个类都是使用final来修饰的。final修饰类后,类不能被继承;修饰方法后,方法不能被子类重写;修饰变量,变量值不能修改,也就是会成为常量。
使用String类中的split方法。如下所示:
str.split(",");
例如:将字符串“23,12,45,33,56,78”转换为数组?
String str = "23,12,45,33,56,78";
String[] strArray = str.split(",");
8进制的值以0开头;16进制的值以0x开头。
可以存储,因为char类型存储是unicode字符。
boolean类型有两个值,分别为true和false。在Java中不能使用0和1来替代这两个值。
switch用于等值判断,而多重if不仅可以等值判断还可以区间判断。
静态方法使用 类名.方法名 的形式来调用,当然也可以用 类的对象 来调用。
静态方法中不可以调用普通方法,但是在普通方法转可以调用静态方法。
(参考资料(需):https://rerun.me/2013/06/13/quicksorting-3-way-and-dual-pivot/)
(1)单路快排
Java学习手册:(数据结构与算法-排序)快速排序
(2)三路快排
Java学习手册:(数据结构与算法-排序)三路快排
(3)双路快排
常量池存储的是:
1、字面量(Literal)
文本字符串等---->用双引号引起来的字符串字面量都会进这里面
2、符号引用(Symbolic References)
①类和接口的全限定名(Full Qualified Name)
②字段的名称和描述符(Descriptor)
③方法的名称和描述符
注:字符串常量池只存储引用,不存储内容!
JVM规范让每个Java线程拥有自己的独立的JVM栈,也就是Java方法的调用栈。
当方法调用的时候,会生成一个栈帧。栈帧是保存在虚拟机栈中的,栈帧存储了方法的局部变量表、操作数栈、动态连接
和方法返回地址等信息。
线程运行过程中,只有一个栈帧是处于活跃状态,称为“当前活跃栈帧”,当前活动栈帧始终是虚拟机栈的栈顶元素。
内存可见性(Memory Visibility):所有线程都能看到共享内存的最新状态。
Java通过几种原子操作完成工作内存和主内存的交互:
volatile关键字的特殊规则就是:
read、load、use动作必须连续出现。
assign、store、write动作必须连续出现。
所以,使用volatile变量能够保证:
IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等。
所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需
要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的
文件。
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传
统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查
找依赖对象的控制权交给了容器,由容器进行注入组合对象,所以对象与对象之间是松散耦合,这样也方便测试,利于功
能复用,更重要的是使得程序的整个体系结构变得非常灵活。
LRU算法的设计原则是:如果一个数据在最近一段时间没有被访问到,那么在将来它被访问的可能性也很小。也就是说,
当限定的空间已存满数据时,应当把最久没有被访问到的数据淘汰。
实现LRU:
1、用一个数组来存储数据,给每一个数据项标记一个访问时间戳,每次插入新数据项的时候,先把数组中存在的数据项的
时间戳自增,并将新数据项的时间戳置为0并插入到数组中。每次访问数组中的数据项的时候,将被访问的数据项的时间戳
置为0。当数组空间已满时,将时间戳最大的数据项淘汰。
2、利用一个链表来实现,每次新插入数据的时候将新数据插到链表的头部;每次缓存命中(即数据被访问),则将数据移
到链表头部;那么当链表满的时候,就将链表尾部的数据丢弃。
3、利用链表和hashmap。当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到
链表头部,如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。在访问数据的
时候,如果数据项在链表中存在,则把该节点移到链表头部,否则返回-1。这样一来在链表尾部的节点就是最近最久未访
问的数据项。
对于第一种方法,需要不停地维护数据项的访问时间戳,另外,在插入数据、删除数据以及访问数据时,时间复杂度都是
O(n)。对于第二种方法,链表在定位数据的时候时间复杂度为O(n)。所以在一般使用第三种方式来是实现LRU算法。
使用反射的getDeclaredFields()可以获得其声明的字段。如果字段是private的,需要调用该字段的f.setAccessible(true);,才能读取和修改该字段。得到了map,再转成JSON标准格式就好了。
(1)常用的散列方法
(2)解决哈希冲突的方法: