前言
上学期Java没好好学,重新学习下,定期学完整理下笔记,做个总结。
- 如果有错误欢迎指出
编译流程
.java
-> .class
-> 执行.class
缩写 | 全称 | 英文全称 | 解释 |
---|---|---|---|
jvm | Java虚拟机 | Java virtual machine | |
jre | Java运行环境 | Java runtime environment | jvm + 核心类库 |
jdk | Java开发工具包 | Java development kit | jre+运行环境工具 |
jvm
< jre
< jdk
创建String流程
两种方式创建区别
String a = "hello"; String b = "hello"; System.out.println(a==b); String c = new String("hello"); String d = new String("hello"); System.out.println(c==d);
true false
原因分析
虚拟机内存划分(涉及本次)
区域 | 包括 |
---|---|
方法区 | 常量池,静态变量等 |
栈 | 基本类型,引用类型 |
堆 | 对象的实例(new) |
对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
而对于字符串来说,其对象的引用都是存储在栈中的,如果是编译期已经创建好(即指用双引号定义的)的就存储在常量池中,如果是运行期(new出来的对象)则存储在堆中。对于equals相等的字符串,在常量池中是只有一份的,在堆中则有多份。
创建 String
,先在 常量池
中寻找,如果有,则直接使用,如果无,则创建后放入 常量池
,并使用
- 使用
String str = ""
创建在栈
中创建str
,指向常量池
(如果常量池
中无则创建,否则直接使用) - 使用
new
创建在堆
中创建一个常量池
对象的拷贝对象(如果常量池
中无则创建,否则直接使用)。栈
中创建引用
指向堆
中拷贝对象。 区别:
- 如果使用字面量,则从
常量池
中找 - 如果使用
new
,则从堆
中创建,而堆
又会从常量池
中找 - 如果想
new
后从常量池
中获取,可以使用inter()
。如上代码。
System.out.println(c.intern() == a); true
- 如果使用字面量,则从
例题:
String str = new String("hello")
创建了多少个对象?- 如果
常量池
中不存在:则产生2个对象
和1个引用
- 如果之前存在,则产生1个
对象
和1个引用
- 如果
String str = new String("a" + "b")
产生多少个对象?(常量池为空,不含引用)4个 (常量池中)a + b + ab + 堆中1个String str = new String("a") + "a"
产生多少个对象?(常量池为空,不含引用)
3个 (常量池中)a + aa + 堆中1个
访问修饰符
访问修饰符 | 本类 | 同包 | 子类 | 其他 |
---|---|---|---|---|
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
继承/代码块/重写和重载
- 子类继承父类:
private,构造方法
是不能被继承的。但是子类
可以调用父类构造super
代码块:
- 静态代码块:永远只执行一次。初始化。
- 普通代码块:每次在
被创建
之前执行。 执行顺序:
- 父类static
- 子类static
- 父类普通
- 父类构造
- 子类普通
- 子类构造
重写和重载(Override/Overload)
位置 | 方法名 | 参数表 | 返回值 | 访问修饰符 | |
---|---|---|---|---|---|
方法重写 | 子类 | 相同 | 相同 | 相同或者是其子类 | 不能比父类更严格 |
方法重载 | 同类 | 相同 | 不相同 | 无关 | 无关 |
抽象类/final
抽象类
class abstract t {
public abstract void a();
}
抽象类
不能被实例化,因为可能存在抽象方法
,而抽象方法
没有方法体
抽象方法
必须在抽象类
中。抽象类
中,并不一定包含抽象方法
final
修饰对象 | 限制 |
---|---|
类 | 不能被继承 |
方法 | 不能被重写 |
变量 | 不能被修改 |
多态
父类 引用对象名 = new 子类()
`double d = 10 //大范围类型 = 小范围类型`
多态实现方法:
- 方法重载
- 方法重写
- 使用
父类
作为方法的形参
- 使用
父类
作为方法的返回值
- 判断父子类:
对象 instanceof 类型
接口
public interface Person {
//1.属性全部是static final类型
//2.方法全是public abstract
void a();
int b();
}
接口
比 抽象类
更进一步 "抽象"
- 继承:is a接口:has a
- 父类 -> 子类 -> A extends B{}接口 -> 实现类 -> A implements B{}
- 类:单继承;接口:接口之间可以相互继承,多继承。
接口
不存在构造方法
- 当
类
实现接口
的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。 - 接口回调:以后填坑。
值传递/引用传递
基本类型
作为参数传递,值不变。引用类型
作为参数传递,值改变。
Lambda入门(Java8)
- 作用:简化代码
组成:
- 逗号隔开的参数列表(a, b, c)
- 箭头符号 ->
- 方法体(λ代码块)
- 要求重写的
接口,抽象类
中 有且只有一个抽象方法
- 函数式接口:@FunctionalInterface 有且只有一个抽象方法
- lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
- 如果主体包含了一个语句,就不需要使用大括号。也不需要引号
public static void main(String[] args) {
new Thread(
() -> System.out.print("hello")
).start();
}
内部类
套娃有点脑壳痛QAQ
分类:
成员内部类
- 内用外,随意
- 外用内,需要内部类对象
外部类名称.内部类名称 对象名 = new 外部类名称().内部类名称();
局部内部类
定义在方法内部
class name { //没有权限修饰符 }
匿名内部类
实现:
new Interface() { // Anonymous class body goes here }
- 接口名 就是
匿名内部类
要实现哪个接口
- 创建的
类
只能使用一次。
多线程
创建线程:
都要重写 run方法
MyThread继承Thread(本质也是实现Runnable)
public class tmp { public static void main(String[] args) { MyThread m = new MyThread(); m.start(); } } class MyThread extends Thread { public void run() { // TODO Auto-generated method stub System.out.print("hello"); } }
实现Runnable接口
public class tmp { public static void main(String[] args) { dou d = new dou(); Thread t = new Thread(d); t.start(); } } class dou implements Runnable { @Override public void run() { // TODO Auto-generated method stub System.out.print("hello"); } }
线程同步
- 多线程访问了共享的数据,会产生线程安全问题。
如何解决:
同步代码块
Object obj = new Object() synchronized(obj) { //访问共享数据的代码 }
同步方法
public synchronized void payTicket() { if() //卖票 }
锁机制
private final ReentrantLock lock = new ReentrantLock(); public void demo() { lock.lock(); try { } finally { lock.unlock(); } }
异常
- 运行时异常:代码在编辑时,不报错,运行时才报错。语法上,可选择处理。
- 检查异常:代码在编辑时,报错。编辑时必须处理。
- 关键字:
try catch finally throws throw
- 如果
try
中出现异常,则跳过异常后代码,跳转到catch
中
try catch
当前方法能够处理。
throws
当前方法不能处理,上交到 方法调用处 处理。
- main函数 再向上抛出 给 JVM
finally
无论正常,异常,始终执行的代码。
- 即使遇到return,也会执行。
- 除非虚拟机关闭,不会执行。
System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序
throw
声明异常throw new MyException("msg");
自定义异常
- 继承Exception,调用
Super(msg)
常用方法
e.printStackTrace();
e.getMessage();
版权属于:moluuser
本文链接:https://archive.moluuser.com/archives/15/
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。