解释说明
姓名 | 职位 | 动作 |
---|---|---|
张三 | 程序员 | 打卡,开会 |
李四 | 前台 | 打卡,开会 |
王五 | 财务 | 打卡,开会 |
用表格表示一组数据,表结构理解为类,每一行数据对应一个对象;
姓名、职位相当于类中的属性;
动作早会相当于类中的方法;
面向过程:执行者思维,对于简单问题,比如开车步骤 按照1234步骤完成即可,思考怎么用;
面向对象:设计者思维,对于复杂的事物,如造车,思考的是怎么设计,如何造车
Object-Oriented Analysis:面向对象分析
Object Oriented Programming:面向对象设计
面向对象离不开面向过程,宏观上面向对象设计,微观上执行和处理数据仍然是面向过程;
总结:
类可以看成一类对象的的模板,对象可以看成该类的一个具体实例。
类用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所具有的共同的属性、方法。
package com.bhzt.base;
import javax.lang.model.element.Name;
public class ObjectOriented {
//属性
public String name;
public String title;
//方法
public void work()
{
System.out.println(name+"的职位为"+title+",开始打卡");
System.out.println(name+"的职位为"+title+",开始开会");
}
//构造方法
public ObjectOriented(){
}
}
package com.bhzt.test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.bhzt.base.ObjectOriented;
class ObjectOrientedTest {
@BeforeEach
void setUp() throws Exception {
}
@Test
void ObjectOrented() {
ObjectOriented objectoriented=new ObjectOriented();
objectoriented.name="zhangsan";
objectoriented.title="develop";
objectoriented.work();
}
}
package com.bhzt.base;
import javax.lang.model.element.Name;
public class ObjectOriented {
//属性
public String name;
public String title;
private double x;
private double y;
/**
* 无惨构造方法
* 1.通过new关键字调用
* 2.有返回值,但不能定义返回类型,不能在构造方法里return 返回值
* 3.如果没有定义构造方法,则编译器会自动定义一个无参的构造方法
* 4.方法名与类名相同
*/
public ObjectOriented(){
}
/**
* 带参数构造方法
* @param name
* @param title
*/
public ObjectOriented(String name,String title){
this.name=name;
this.title=title;
}
public ObjectOriented(double x,double y)
{
this.x=x;
this.y=y;
}
//方法
public void work()
{
System.out.println(name+"的职位为"+title+",开始打卡");
System.out.println(name+"的职位为"+title+",开始开会");
}
/**
* 计算距离
* @param ob
* @return
*/
public double getDistance(ObjectOriented ob)
{
double _x=x-ob.x;
double _y=y-ob.y;
return Math.sqrt(_x*_x+_y*_y);//开平方
}
}
package com.bhzt.test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.bhzt.base.ObjectOriented;
class ObjectOrientedTest {
@BeforeEach
void setUp() throws Exception {
}
@Test
void workTest() {
ObjectOriented objectoriented=new ObjectOriented();
objectoriented.name="zhangsan";
objectoriented.title="develop";
objectoriented.work();
ObjectOriented objectoriented2=new ObjectOriented("lisi", "sale");
objectoriented2.work();
}
@Test
void getDistanceTest()
{
ObjectOriented o1=new ObjectOriented(3.0,4.0);
ObjectOriented o2=new ObjectOriented(0,0);
System.out.println(o1.getDistance(o2));
}
}
JVM
内存分析
从属于线程的区域
JVM内存划分中,有部分区域是线程私有的。
程序计数器:记录程序执行到了哪一步,当线程暂停在重新启动时,则从上次执行到的位置开始执行;每个线程都有自己的程序计数器。这是一个比较小的内存空间,存储当前线程正在执行的java方法的jvm指令地址,既字节码的行号。如果正在执行的是native方法,则这个计数器为空。
虚拟机栈:每个线程在创建的时候都会创建一个虚拟机栈,生命周期与线程一致,线程退出时,线程的虚拟机栈也回收。虚拟机栈内保持一个个的栈帧,每次方法调用都会进行压栈,jvm对栈帧的操作只有出栈和压栈,方法调用结束时会进行出栈。该区域存储局部变量表,编译时期可知的各种基本类型数据、对象引用、方法出口等信息。
本地方法栈:调用本地方法时使用的栈。
堆 heap
几乎所有创建的java对象实例,都是会直接分配到堆上。
堆被所有的线程所共享,在堆上的区域会被垃圾回收器做进一步的划分,如新生代,老年代。java虚拟机在启动的时候可以配置堆区域的大小。
方法区
所有线程共享,存储不变的数据;
运行时常量池
字符串常量,符号引用
直接内存
栈、堆特点
虚拟机栈(简称:栈)
1.每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
2. JVM为每个线程创建一个栈,存放该线程执行方法的信息
3. 栈属于线程私有,不能实现线程间共享
4. 存储特性,先进后出 后进先出
5. 栈是由系统自动分配,速度快,是一个连续的内存空间
堆:
1.用于存储创建好的对象和数组(数组也属于对象)
2.JVM只有一个堆,被所有线程共享
3.堆是一个不连续的内存空间,分配灵活 速度慢
方法区:
实际也属于堆,只是用于存储类、常量相关信息
package com.bhzt.base;
public class Person {
public String name;
public int age;
public void show() {
System.out.println("姓名:"+name+",年龄:"+age);
}
}
package com.bhzt.test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.bhzt.base.Person;
class PersonTest {
@BeforeEach
void setUp() throws Exception {
}
@Test
void showTest()//step0
{
Person p1=new Person();//step1
p1.name="张三";//step2
p1.age=20;//step3
p1.show();//step4
Person p2=new Person();//step5
p2.name="李四";//step6
p2.age=30;//step7
p2.show();//step8
}
}
垃圾回收机制
Garbage Collection
由GC线程自动回收垃圾,主要回收堆里的垃圾,没有任何变量引用的对象被GC通过算法进行回收
GC算法:
1.引用计数器
当引用数为0时,则视为可回收
优点:算法简单
缺点:循环引用的无用对象 无法识别
package com.bhzt.base;
public class Person {
public String name;
public int age;
Person p;
public void show() {
System.out.println("姓名:"+name+",年龄:"+age);
}
/**
* 循环引用,GC引用计数器无法识别
*/
public void test1() {
Person p1=new Person();
Person p2=new Person();
p1.p=p2;
p2.p=p1;
p1=null;
p2=null;
}
}
2.引用可达法
分代垃圾回收机制
1.年轻代
Eden、Survivor
所有新生成的对象放到Eden区,由Minor GC清理生命周期短的对象。
Eden区满了,触发一次Minor GC。清理无用对象,将有用对象复制到Survivor1,Survivor2区中,仍然有用的对象循环存放到s1 or s2,当Minor GC对同一对象清理次数达到15次 仍有效则放到Tenured区。
2.年老代
Tenured/Old 空间
在年轻代中经历了N(默认15)次垃圾回收仍然存活的对象,就会被放到年老代中。当年老代对象越来越多时,就需要启动Major GC和Full GC(全量回收)
Major GC:清理Tenured代空间。
Full GC:清理年轻代和年老代。
3.永久代
存放静态文件,如java类、方法等。
JVM调优
对FULL GC的调节,如下情况会导致FULL GC:
1.年老代被写满
2.永久代被写满
3.System.gc()被显示调用,该方法只是建议JVM清理,不是直接调用FULL GC(),程序员无权调用垃圾回收器,finalize是java提供给程序员用来释放对象或资源的方法,但尽量少用
4.上次GC后,Heap的各域分配策略动态变化
总结
1.创建大量无用对象
比如,for循环拼接字符串,使用了String 而不是StringBuilder,String是对象
String str="";
for(int i=0;i<=100;i++)
{
str += i; //产生了100个String对象
}
2.静态集合类的使用
像HashMap、Vector、List等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,所有的对象也不被释放。
3.各种连接对象未关闭
IO流对象、数据库连接对象、网络连接对象等属于物理连接,和硬盘或者网络连接,不使用的时候一定要关闭
4.监听器的使用
释放对象时,没有删除相应的监听器
this static关键字
this:创建好的对象的地址
创建一个对象分4步:
1.分配对象空间,并将对象成员变量初始化
2.执行属性值的显示初始化
3.执行构造方法
4.返回对象的地址给相关的变量
this不能放在static方法里
static:用此声明的成员变量为静态变量,也称类变量。类变量的生命周期与类相同。
package com.bhzt.base;
public class PersonTow {
public String a;
public static String b;//静态变量,存储在方法区
public void getA() {
System.out.println(a);
System.out.println(b);
}
/**
* 静态变量存储在方法区
*/
public static void getB() {
//System.out.println(a);//不能调用对象属性,只能调用方法区属性
//this.a //this指的是创建好的对象地址,静态区方法不能直接调用对象里的变量,需要先创建对象
System.out.println(b);
}
}
@Test
void getA()
{
PersonTow pt=new PersonTow();
pt.a="aaa";
pt.getA();
}
/**
* 做类的静态初始化
*/
static {
b="bbb";
}
包机制
包起名采用域名倒着写,如com.taobao.
com.taobao.test
以上两个包虽然有逻辑的关系(文件件包含),但实际上是单独的两个个体