java在DOS中编译和运行
- 带包编译:
文件根目录 javac 文件名.java- 例子:javac HelloWorld.java
- 带包运行:
包根目录 java 包名.类名 参数1 参数2- 例子:java com.sean.test.HelloWorld arg1 arg2
- jar包运行:
java -jar jar包目录\jar包名称.jar 参数1 参数2- 例子:java -jar E:\jar\util.jar arg1 arg2
JDK和JRE区别
JDK包含JRE,JRE包含了jvm和基础的jar,但是JDK包含了更多的工具,例如jconsole,jvisualvm等工具软件,以及java程序员编写的所需的文档
关键字
- 不常用字段解释
- strictfp:在接口和类上加上该标识,会对float和double进行严格计算
- transient:在对象成员变量中加上该标识,在对象序列化时,被标识变量不会被序列化
- volatile:在变量前加入该标示,解决多线程情况下变量的可见性和有序性,但无法解决原子性问题,应用场景为,变量的值不参与修改的情况。参见:Java并发编程:volatile关键字解析
- finalize :Object的方法,非关键字,作用是垃圾回收前调用
this
作用:
- 解决了局部变量隐藏成员变量的问题
static关键字
- 特点: 1.1 随着类的加载而加载 1.2 优先于对象存在 1.3 被类的所有对象共享 1.4 既可以通过类名调用,也可以通过对象名调用
1.5 静态方法能够继承但不能重写
- 内存图 静态的内容在方法区的静态区
jdk1.8,静态变量和静态方法放在堆中,类的Class对象存储在堆中,类的元信息(class文件内容)存储在元空间中
- 注意事项 3.1 静态方法中没有this对象 3.2 静态只能访问静态
final关键字
(1)是最终的意思,可以修饰类,方法,变量。
(2)特点:
A:它修饰的类,不能被继承。
B:它修饰的方法,不能被重写。
C:它修饰的变量,是一个常量。
(3)面试相关:
A:局部变量
a:基本类型 值不能发生改变
b:引用类型 地址值不能发生改变,但是对象的内容是可以改变的
B:初始化时机
a:只能初始化一次。
b:常见的给值
定义的时候。(推荐)
或者静态代码块中。
构造方法中。
注意事项:
类名前
不使用:
private、protected、static
使用:
权限修饰符:默认修饰符,public
状态修饰符:final
抽象修饰符:abstract
成员变量
不使用:
abstract
使用
权限修饰符:private,默认的,protected,public
状态修饰符:static,final
数据类型
-
基本数据类型
A:整数 占用字节数 byte 1 short 2 int 4 long 8 B:浮点数 float 4 double 8 C:字符 char 2 D:布尔 boolean 1
注意:!!!!!
整数默认是int类型,浮点数默认是double。
长整数要加L或者l。
单精度的浮点数要加F或者f。
思考题和面试题
-
下面两种方式有区别吗?
float f1 = 12.345f; // 本身是一个float类型 float f2 = (float)12.345; // 开始是一个double类型,强转为float类型
-
下面的程序有问题吗,如果有,在哪里呢?
byte b1 = 3; byte b2 = 4; byte b3 = b1 + b2; // 有问题,byte参与运算就转换为int类型,编译会报错 byte b4 = 3 + 4; // 常量,先把结果计算出来,然后看是否在byte的范围内,如果在,就不报错
-
下面的操作结果是什么呢?
byte b = 130; // 编译报错,130不在范围内 byte b = (byte)130; // -126 源码反码补码!???
-
字符参与运算
是查找ASCII里面的值 'a' 97 'A' 65 '0' 48
System.out.println('a'); // a System.out.println('a' + 1); // 98 -
字符串参与运算
这里其实是字符串的连接
System.out.println("hello"+'a'+1); // helloa1 System.out.println('a'+1+"hello"); // 98hello System.out.println("5+5="+5+5); // 5+5=55 System.out.println(5+5+"=5+5"); // 10=5+5
字符串
面试题1:
String s = new String("hello");和String s = "hello"的区别? 前者有两个地址值,一个是在方法区的常量的地址值,另一个是new String()的地址值,有两个对象 后者是直接赋值,到方法区去找他的地址只有一个对象
面试题2:
String s1 = "hello"; String s2 = "world"; String s3 = "helloworld"; System.out.println(s3 == s1 + s2);// false s1+s2会在堆中新建一个地址,地址值不相同(+会重新new一个对象) System.out.println(s3.equals((s1 + s2)));// true
System.out.println(s3 == "hello" + "world");// false 这个我们错了,应该是true,原因是像 String s3 = "hello" + ",world" 这样直接两个字面值相加的,java文件在编译期间就已经将这条语句做了优化,将其直接变成 "hello,world",等到运行的时候就查找字符串常量池,因此 s3 == s4 返回的结果就为 true。
System.out.println(s3.equals("hello" + "world"));// true
面试题3:
String,StringBuffer,StringBuilder的区别 String: 内容是不可变的 StringBuffer: 是一个容器,内容是可变的,同步的,线程安全,效率低 StringBuilder: 也是一个容器,内容是可变的,不同步的,线程不安全,效率高
面试题4:
StringBuffer是如何实现线程安全的: 除构造方法外和部分insert和indexOf方法外,都使用了在方法上加同步锁的方式保证线程安全,而未加锁的insert和indexOf方法是通过调用父类,父类再调用其本身的已加锁的方法保证线程安全。
Integer
面试题1:
-128到127之间的数据缓冲池问题 但特殊和要注意的是: 若传入的是 -128~127 的值,则不是引用类型,而是类似 于基本类型的常量池中的值,故而可以用 == 号去判断 即: new Integer(127)==new Integer(127); //true
运算符
赋值运算符
扩展的赋值运算符的特点 隐含了自动强制转换。
面试题:
short s = 1;
s = s + 1;(编译错误)
short s = 1;
s += 1;(<==>s=(short)(s+1))
// 请问上面的代码哪个有问题?
位运算
| 位运算符 | 说明 |
|---|---|
| >> | 右移运算符,符号左侧数值 按位右移 符号右侧数值指定的位数,若为正数则高位补0,若为负数则高位补1 |
| << | 左移运算符,符号左侧数值 按位左移 符号右侧数值指定的位数,并在低位处补0 |
| >>> | 无符号右移运算符,符号左侧数值 按位右移 符号右侧数值指定的位数,无论正负高位补0 |
| & | 与(AND)运算符,对两个整型操作数中对应位执行布尔代数,两个位都为1时输出1,否则0 |
| | | 或(OR)运算符,对两个整型操作数中对应位执行布尔代数,两个位中只要有一个为1就输出1,否则为0 |
| 异或(XOR)运算符,对两个整型操作数中对应位执行布尔代数,两个位相等则为0,不相等则为1 | |
| ~ | 非(NOT)运算符,按位取反运算符翻转操作数的每一位,即0变成1,1变成0 |
方法
java内存分配
- 栈:存储局部变量(在方法定义中或者方法申明上定义的变量)以及常量值 数据使用完毕就消失
- 堆:存储所有new出来的对象 每一个new出来的东西都有地址 每一个变量都有默认值 byte,short,int,long 0 float,double 0.0 char '\u0000' boolean false 引用类型 null 数据使用完毕后,在垃圾回收器空闲的时候回收。
- 方法区:
class内容区域:文件中的内容,包含成员变量和成员方法,每个class的方法会有一个地址,为堆中的调用提供连接
静态区:静态变量和静态方法
- 本地方法区:与本地系统相关
- 寄存器:CPU相关
创建对象,内存的流程图:
(1)把Student.class文件加载到内存
(2)在栈内存为s开辟空间
(3)在堆内存为学生对象申请空间
(4)给学生的成员变量进行默认初始化。null,0
(5)给学生的成员变量进行显示初始化。林青霞,27
(6)通过构造方法给成员变量进行初始化。刘意,30
(7)对象构造完毕,把地址赋值给s变量
成员变量和局部变量区别
- 在类中的位置 成员变量:类中,方法外 局部变量:在方法中或方法声明上
- 在内存中的位置 成员变量:堆 局部变量:栈
- 初始化的值 成员变量:有默认值 局部变量:没有默认值,只有定义,赋值,才能使用
- 生命周期 成员变量:随着对象的创建而创建,随着对象的消失而消失 局部变量:随着方法的调用而存在,随着方法的结束而消失
构造方法
- 格式:
- 方法名和类名相同
- 没有返回值类型,void也没有
- 没有返回值
思考题:构造方法中可不可以有return语句呢? *****
可以。而是我们写成这个样子就OK了:return;
其实,在任何的void类型的方法的最后你都可以写上:return;
代码块执行顺序
看程序写结果:
A:一个类的静态代码块,构造代码块,构造方法的执行流程
静态代码块 > 构造代码块 = 显示初始化 (看顺序) > 构造方法
B:静态的内容是随着类的加载而加载
静态代码块的内容会优先执行
C:子类初始化之前先会进行父类的初始化
注: 类成员变量的初始化顺序:显式初始化与构造代码块的初始化等级一致,故由代码顺序决定初始化顺序,但注意的是构造代码块不能加数据类型
结果是:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
class Fu {
static {
System.out.println("静态代码块Fu");
}
{
System.out.println("构造代码块Fu");
}
public Fu() {
System.out.println("构造方法Fu");
}
}
class Zi extends Fu {
static {
System.out.println("静态代码块Zi");
}
{
System.out.println("构造代码块Zi");
}
public Zi() {
System.out.println("构造方法Zi");
}
}
class ExtendsTest2 {
public static void main(String[] args) {
Zi z = new Zi();
}
}
方法重写和方法重载的区别
- 方法重写:方法名,参数和返回值都相同
- 方法重载:方法名相同,参数不同,与返回值无关
继承
继承的好处
A:提高了代码的复用性 B:提高了代码的维护性 C:让类与类产生了一个关系,是多态的前提
继承的弊端
A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。 原则:低耦合,高内聚。 耦合:类与类的关系 内聚:自己完成某件事情的能力 B:打破了封装性
继承的成员关系
A:成员变量 a:子类的成员变量名称和父类中的成员变量名称不一样,这个太简单 b:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢? 子类的方法访问变量的查找顺序: 在子类方法的局部范围找,有就使用。 在子类的成员范围找,有就使用。 在父类的成员范围找,有就使用。 找不到,就报错。 B:构造方法 a:子类的构造方法默认会去访问父类的无参构造方法 是为了子类访问父类数据的初始化 b:父类中如果没有无参构造方法,怎么办? 子类通过super去明确调用带参构造 子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造 让父类提供无参构造
注意事项:
this(...)或者super(...)必须出现在第一条语句上,否则会出现编译错误。
如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。
多态
多态中的成员访问特点
A:成员变量
编译看左边,运行看左边
B:构造方法
子类的构造都会默认访问父类构造
C:成员方法
编译看左边,运行看右边
D:静态方法
编译看左边,运行看左边
(静态和类相关,算不上重写,所以,访问还是左边的)
多态继承中的内存图解
多态中的对象变化内存图解
面试题
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
/*
public void show() {
show2();
}
*/
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show() {
super.show();
}
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show();// 爱
B b = new C();
b.show();// 你
}
}
抽象类
抽象类的特点
A:抽象类和抽象方法必须用关键字abstract修饰
B:抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类
C:抽象类不能实例化
D:抽象类的子类
a:是一个抽象类。
b:是一个具体类。这个类必须重写抽象类中的所有抽象方法。
抽象类的问题
A:抽象类有构造方法,不能实例化,那么构造方法有什么用?
用于子类访问父类数据的初始化
B:一个类如果没有抽象方法,却定义为了抽象类,有什么用?
为了不让创建对象
C:abstract不能和哪些关键字共存
a:final 冲突
b:private 冲突
c:static 无意义
抽象类与接口的区别
- 抽象类与子类是 is 的关系,接口是 like 的关系,抽象类耦合度更高,有更好的复用性和维护性,接口反之
- 抽象类只能被单继承,而接口,子类可以实现多个
- 抽象类可以有非常量的成员变量,接口只能有常量的成员变量,接口在1.8后有默认方法,抽象类具有成员方法
接口
接口的成员特点
A:成员变量
只能是常量
默认修饰符:public static final
B:构造方法
没有构造方法
C:成员方法
只能是抽象的
默认修饰符:public abstract
类与类,类与接口,接口与接口
A:类与类
继承关系,只能单继承,可以多层继承
B:类与接口
实现关系,可以单实现,也可以多实现。
还可以在继承一个类的同时,实现多个接口
C:接口与接口
继承关系,可以单继承,也可以多继承
内部类
内部类访问规则
A:可以直接访问外部类的成员,包括私有 B:外部类要想访问内部类成员,必须创建对象
成员内部类
- 成员内部类不是静态的: 外部类名.内部类名 对象名 = new 外部类名.new 内部类名();
- 成员内部类是静态的: 外部类名.内部类名 对象名 = new 外部类名.内部类名();
30,20,10
class Outer {
public int num = 10;
class Inner {
public int num = 20;
public viod show() {
int num = 30;
System.out.println(num);
System.out.println(this.num);
System.out.println(Outer.this.num);
}
}
}
局部内部类
A:局部内部类访问局部变量必须加final修饰。
B:为什么呢?
因为局部变量使用完毕就消失,而堆内存的数据并不会立即消失。
所以,堆内存还是用该变量,而该变量已经没有了。
为了让该值还存在,就加final修饰。
C:匿名内部类是局部内部类的简化形式
D:匿名内部类的面试题(补齐代码)
interface Inter {
void show();
}
class Outer {
//补齐代码
public static Inter method() {
return new Inter() {
public void show() {
System.out.println("HelloWorld");
}
};
}
}
class OuterDemo {
public static void main(String[] args) {
Outer.method().show(); //"HelloWorld"
}
}
复制
浅复制:
将基本数据类型的值进行复制和引用类型的地址进行复制
深复制:
将基本类型的值和引用类型的值进行复制
异常
Error和Exception区别
error一般为jvm的错误,如系统奔溃,虚拟机出错误
运行时异常和非运行时异常有何区别
运行时异常为非检查异常,一般在程序运行时产生的异常,而非运行时异常会有编译错误,需要进行抛出或try,catche处理
列举5个非运行时异常
空指针异常
数组越界异常
字符串越界异常
类型转换异常
数字计算异常
反射
反射的用途
- 在运行时,根据类型创建对象,调用方法,对其赋值,在spring的依赖注入中用到
- IDE的代码补齐以及查看类的成员变量和成员方法
序列号
什么是序列化和反序列化
序列化是java对象转换为字节数组的过程
反序列化是字节数组转换为java对象的过程
Serializable 和 SerializableID的作用
Serializable 接口若不实现,在调用 ObjectOutputStream#writeObject和ObjectInputStream#readObject这两个方法时,会抛出异常 NotSerializableException
SerializableID的作用是序列化时作为一个对象的标识,若没有该标识,则会根据序列化的字段自动生成一个SerializableID的值,后续进行反序列化时,若修改了成员变量,该值改变,则无法反序列化成功,若定义了一个常量值,即使修改成员变量,依然可以反序列化成功