JVM内存模型
-
堆
堆是 JVM 内存中最大的一块内存空间,该内存被所有线程共享,几乎所有对象都被分配到了堆内存中
-
方法区
方法区主要是用来存放已被虚拟机加载的类相关信息,包括类信息、常量池等信息
-
程序计数器
是一块很小的内存空间,主要用来记录各个线程执行的字节码的地址,例如分支、循环、跳转、异常、线程恢复等都依赖于计数器。
-
虚拟机栈[方法栈]
当创建一个线程时,开辟一个虚拟机栈空间,用来保存方法的局部变量和返回地址等信息
每一个方法的调用都伴随着栈帧的入栈操作,方法的返回则是栈帧的出栈操作。
-
本地方法栈 native
本地方法栈跟虚拟机栈的功能类似,虚拟机栈用于管理 Java 方法的调用,而本地方法栈则用于管理本地方法的调用。
但本地方法并不是用 Java 实现的,而是由 C 语言实现的。
模拟栈溢出
public class Test{
public static void main(String [] args){
say("hello");
}
public static void say(String content){
System.out.println(content);
say(content);
}
}
模拟堆溢出
public class Test{
int [][][] data = new int [10000][10000][10000]; //自行调整大小
public static void main(String [] args){
//创建一个占用空间很大的对象
new Test();
}
}
Static修饰符
含义
用来修饰方法、成员变量(常量),代表这些属于类级别的,可以直接通过类名.来调用【推荐】。也可以通过对象.来调用
类成员
含义
用static修饰成员变量(常量),代表这些属于类级别的。
特点
-
随着类加载而初始化,全局只有一份,所有对象共享
-
类名.成员变量(常量)来调用
类方法
含义
static 修饰的方法
特点
- 属于类级别的,类名.方法名([参数类表])方式来调用
- static方法只能访问static方法或static成员变量(常量)
- 非static方法可以访问static方法或static成员变量(常量)
使用场景
- 一般作为工具类(自行查看Arrays的方法)
成员变量细分
static
非static
成员方法细分
static
非static
变量分类&生命周期
变量种类 | 存放位置 | 生命周期开始 | 生命周期结束 |
---|---|---|---|
局部变量 | 方法里面的 | 方法调用开始 | 方法调用结束 |
类成员变量(static) | 和方法级别 | 类的加载开始 | 类的卸载结束 |
对象成员变量(非static) | 和方法级别 | 对象的创建 | 对象被回收 |
Package
含义
是类的容器,在磁盘中以文件夹的方式存在
作用
- 归类,将同类功能的类放入相同的包
- 避免名字相同的类名冲突
语法规范
- 公司域名倒写,遇到数字前面添加_
- 全部小写
常见的包名
- java.lang [此处会自动导入包]
- java.text 比如SimpleDateFormat
- java.util 比如List
- java.net
- …
Import
含义
import就是在java文件开头的地方,先说明会用到那些类。在代码中只用类名指定某个类。
语法
-
import 包名.子包N.类名; //导入指定包下的指定类
-
import 包名.子包N.*; //导入子包下的所有类
案例
import java.text.DateFormat;
import java.text.SimpleDateFormat;
public class ImportTest {
public static void main(String[] args) {
//会自动导入java.lang下的类
String name ="test";
SimpleDateFormat simpleDateFormat = null;
DateFormat dateFormat=null;
}
}
封装
含义
将抽象的成员特征和行为放到类中,隐藏内部细节,并对外提供需要访问的接口
为什么封装
TODO
如何隐藏
使用范围修饰符
范围修饰符
含义
控制访问的权限【或可见性】
有哪些
种类 | 同类 | 同包 | 子类不同包 | 其他 |
---|---|---|---|---|
public | y | y | y | y |
protected | y | y | y | n |
默认 | y | y | n | n |
private | y | n | n | n |
使用优先级
private>protected>默认>public
entity
- 私有的字段,根据情况对外setter或getter方法
- 对于boolean型不建议使用is开头的字段
this
含义
当前对象本身
使用场景
- 调用构造器
- 避免参数二义性
- 方法链
注意点
静态方法中不能使用this关键字
继承
含义
在原有的代码结构上扩充新的功能,继承解决的是代码的重复的现象
语法
修饰符 class 类名 extends 父类类名{
//扩展新的功能
}
案例
public class Bird {
private String name;
String sex;
public Bird(){
}
public Bird(String name){
this.name = name;
}
public void eat(){
System.out.println("吃东西");
}
}
//企鹅
public class Pengui extends Bird {
}
public class Ostrich extends Bird {
public static void main(String[] args) {
Ostrich ostrich = new Ostrich();
System.out.println(ostrich.sex);
ostrich.eat();
//Ostrich otherOstrich = new Ostrich("xx");
}
}
注意点
- 类是不能多继承的
- 父类私有方法、字段是不能继承
- public protected修饰的方法、字段可以被继承
- 默认修饰的方法、字段如果不能同一个包则不能继承
- 构造器不能被继承
final修饰符
含义
代表最终
修饰什么
- 字段
- final int age =1; //代表age就是常量
- 类名
- 代表该类不能被其他类继承
- 方法
- 代表该方法不能被重写【TODO】
案例
public class FinalDemo {
//成员常量
final int age=1;
//修饰类
//最终的意思,不能被其他类继承 自行尝试
//修饰方法
//代表该方法不能被重写【TODO】
public void say(){
//局部常量
final int age=1;
}
}
子类实例化过程
过程
在创建子对象会先调用父类的构造器创建父对象
注意点
父类的构造器不能全部都是私有的,根据情况需要指定调用父类的构造器。
案例
public class Animal {
String name;
private Animal(){
System.out.println("父被对象被创建了");
}
public Animal(String name){
this.name = name;
}
}
public class Cat extends Animal{
//子类实例化过程
//在子类的构造器第一行会调用父类的构造器创建父对象
public Cat(){
//隐藏super();
//指定父类可以访问的构造器
super("小花猫");
System.out.println("子对象被创建了");
}
public static void main(String[] args) {
Cat cat = new Cat();
}
}
方法覆盖(重写\覆写)
含义
子类继承了父类的行为,但是有些行为不满足现有要求。
格式
@Override
范围修饰符 返回类型 方法名(){
扩展的需求
}
案例
public class Bird {
private String name;
protected void move(){
System.out.println("翅膀...");
}
public static void destroy(){
}
}
public class Pengui extends Bird {
@Deprecated
private int age;
//此时父类的move不满足要求,可以通过重写
//语法
//编写和父类一样的方法,然后在方法体加以扩展。
//注意点
//范围修饰符只能>=父类方法的。
//不能抛出比原来更大的异常
//final修饰的方法不能被重写
//static修饰的方法不能被重写
@Override //注解 1.5
protected void move(){
System.out.println("脚。。");
}
//注解
//含义
//用来修饰方法、字段、类名、参数名
//常见
//@Override 方法重写
//@Deprecated 代表过时,不建议
public static void main(String[] args) {
Pengui pengui = new Pengui();
}
}
约束
- 范围修饰符只能>=父类方法的。
- 不能抛出比原来更大的异常
- final修饰的方法不能被重写
- static修饰的方法不能被重写
注解
含义
用来修饰方法、字段、类名、参数名
常见
- @Override 方法重写
- @Deprecated 代表过时,不建议
Super(父对象)
含义
父对象
场景
- 子类的构造器显示调用父类的构造器
- 调用父类的方法
- 调用父类的字段【成员变量、成员常量】
案列
public class Animal {
int age;
public Animal(int age){
this.age = age;
}
public void move(){
System.out.println("脚。。。");
}
}
public class Fish extends Animal{
int age;
public Fish(){
super(10);
}
@Override
public void move() {
super.move();
}
public void sayInfo(){
System.out.println("年龄"+super.age);
}
//super
//调用父类构造器
//调用父类方法
//调用父类字段
public static void main(String[] args) {
Fish fish = new Fish();
//fish.move();
fish.sayInfo();
}
}
Object
含义
除了Object之外一切类的超类。
常用方法
- toString
- equals
- getClass
- finilize
- hasCode
案例
public class ObjectTest {
private String name;
//Object
//含义:除了Object之外一切类的超类
//常用的方法
//toString
//getClass
//equals 判断两个对象的地址是否一样,里面使用==,一般根据情况重写该方法
//finilize 当某个对象被GC回收的时候会触发该方法,实际不要去重写
//hasCode
public static void main(String[] args) {
ObjectTest objectTest = new ObjectTest();
System.out.println(objectTest);
System.out.println(objectTest.toString());
//某个类只会加载一次
//User.java --- > User.class --类加载器-->JVM(方法区)
//如何获取User类相关信息
//方式一:对象.getClass();
//其他方式后面回顾
//clazz包含ObjectTest这个类的信息
Class clazz = objectTest.getClass();
//获取包名
System.out.println(clazz.getPackage().getName());
//ObjectTest 类的简单名称
//com.neu._09object.ObjectTest 类名
System.out.println(clazz.getSimpleName());
System.out.println(clazz.getName());
ObjectTest one = new ObjectTest();
ObjectTest two = new ObjectTest();
System.out.println(one.equals(two));
}
}
引用数据类型转换
子类型对象可以自动赋值给父类型对象
父类型对象赋值给子类型对象需要强制转换,如果类型不一样会出现ClassCastException异常
案例
public class Animal {
}
public class Cat extends Animal{
}
public class Fish extends Animal{
}
public class User {
public static void main(String[] args) {
//ClassCastException
Animal cat = new Fish();
//instanceof 用来比较某个对象是否是某类的实例
if(cat instanceof Fish){
Fish fish = (Fish) cat;
System.out.println(fish);
}else if(cat instanceof Cat){
Cat otherCat = (Cat) cat;
System.out.println(otherCat);
}
}
}
多态
含义
同一个对象有多种状态,只有运行的时候才能确定
原理
- 继承
- 实现接口 TODO
案例
public class Animal {
String name;
public Animal(String name){
this.name = name;
}
public void print(){
System.out.println(this.name);
}
}
public class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
public class Fish extends Animal{
public Fish(String name) {
super(name);
}
}
public class Test {
//多态
//含义:同一个对象有多种状态,只有运行的时候才能确定。
//原理
//继承
//实现接口 TODO
public static void main(String[] args) {
Test test = new Test();
Cat cat = new Cat("猫");
test.like(cat);
Fish fish = new Fish("小鱼");
test.like(fish);
}
public void like(Animal animal){
System.out.println(animal);
}
//没有使用多态
/*
public void like(Cat cat){
System.out.println(cat);
}
public void like(Fish fish){
System.out.println(fish);
}
*/
}
代码块
含义
种类
- 静态代码块
- 普通代码块
final
修饰字段=>常量
修饰方法=>该方法不能被重写
修饰类=>该类不能被继承
单例设计模式
含义
某一个类最多只能创建一个实例。
好处
避免重复创建对象
如何实现
- 饿汉式
- 懒汉式
饿汉式
步骤
- 私有的构造器
- 提供static final 修饰的该类型的常量,且赋值为当前单例对象
- 对外提供public static用于获取单例对象
案例
public class ATM {
//只会创建一次
private final static ATM atm = new ATM();
private ATM(){
}
public static ATM getInstance(){
return atm;
}
public void output(int money){
System.out.println("取钱"+money);
}
}
public class User {
public static void main(String[] args) {
ATM atm = ATM.getInstance();
atm.output(2);
ATM other = ATM.getInstance();
//结果为true
System.out.println(atm == other);
}
//ATM 单例
//第一步:避免重复创建对象,private 构造器
//第二步:编写static的变量且初始化
//第三步:提供用于获取实例的方法给外部调用
}
抽象类
含义
abstract 修饰的类
为什么
TODO
案例
自行编写
注意点
- 抽象类中可以没有有抽象方法,可以有普通方法
- 抽象方法一定要在抽象类中
- 抽象方法不能否final修饰的
- 抽象方法不能static的
- 抽象类的构造器不能全部都是私有的
- 抽象类不能是final修饰的
- 抽象类不能直接new
作业
-
自行模拟一个ClassCastException异常-
-
自行编写一个单例
-
自行编写一个抽象类的使用场景
-
思考static 能否修饰局部变量?
-
思考多态的含义、实现原理
-
思考final的使用场景
-
思考四大作用范围的作用域