Java EE基础班课程(第七天)
学习目标:
- 了解类和对象的定义
- 了解对象的内存图
- 理解成员变量和局部变量之间区别
- 理解成员变量和成员方法的使用
- 掌握面向对象的三种特征之一封装(封装,继承,多态)
- 掌握构造方法的使用
- 掌握类的创建,对象创建
- 掌握标准类的编写
1.面向对象入门
1.1面向对象和面向过程的思想对比
面向过程:是一种以过程为中心的编程思想,实现功能的每一步,都是自己实现的
面向对象:是一种以对象为中心的编程思想,通过指挥对象实现具体的功能
面向对象思想小结:
可观存在的任何一种事物,都可以看做为程序中的对象,万物皆对象
使用面向对象思想可以将复杂的问题简单化
将我们从执行者的位置,变成了指挥者
1.2类
类是对现实生活中一类具有共同属性和行为的事物的抽象
类的组成:
属性
该事物的各种特征
例如黑马学生事物的属性:姓名、年龄、毕业院校…
行为
该事物存在的功能(能够做的事情)
例如黑马学生事物行为:学习、Java编程开发
1.3类的定义
类的组成:属性和行为
属性:在类中通过成员变量来体现(类中方法外的变量)
行为:在类中通过成员方法来体现(和前面的方法相比去掉static关键字即可)
类的定义格式:
public class 类名 {
// 成员变量
变量1的数据类型 变量1;
变量2的数据类型 变量2;
…
// 成员方法
方法1;
方法2;
…
}
public class Student {
//年龄 姓名 成员变量 类的属性
String name;
int age;
// 学习 成员方法 类的行为
public void study(){
System.out.println("GOOD GOOD STUDY DAY DAY UP");
}
}
public class Phone {
//成员变量:品牌,价格…
String brand;
double price;
//成员方法:打电话,发短信…
public void call(){
System.out.println("打电话");
}
public void sendMessage(){
System.out.println("发短信");
}
}
1.4对象的定义和使用
定义:是能够看得到摸的着的真实存在的实体
使用对象:
1.创建对象
格式:类名 对象名 = new 类名();
范例:Student s = new Student();
2.使用对象
2.1使用成员变量
格式:对象名.变量名
范例:s.name
2.2使用成员方法
格式:对象名.方法名()
范例:s.study();
public class TestStudent {
public static void main(String[] args) {
//类名 对象名 = new 类名();
Student stu = new Student();
//成员方法的调用
//对象名.方法名
stu.study();
//成员变量
//对象名.属性名
stu.name = "张三";
stu.age = 18;
System.out.println(stu.name);
System.out.println(stu.age);
}
}
//在手机测试类中通过对象完成成员变量和成员方法的使用
public class TestPhone {
public static void main(String[] args) {
//创建对象
Phone p = new Phone();
//成员变量使用
p.brand = "HUAWEI";
p.price = 37999.00;
System.out.println(p.brand);
System.out.println(p.price);
//成员方法使用
p.call();
p.sendMessage();
}
}
2.对象的内存图
3.垃圾回收机制
注意:当堆内存中,对象或数组产生的地址,通过任何方式都不能被找到后,就会被判定为内存中的“垃圾”
垃圾会被Java垃圾回收器,空闲的时候自动进行清理
优点:
垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存
3.1引用计数法(Reference Counting Collector) 其他的想了解自己查资料学习
算法分析
引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,且将该对象实例分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减1。任何引用计数器为0的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减1。
优点:
引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。
缺点:
无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.
3.2GC的执行机制
由于对象进行了分代处理,因此垃圾回收区域、时间也不一样。GC有两种类型:Scavenge GC和Full GC
Scavenge GC
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
Full GC
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个堆进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:
1.年老代(Tenured)被写满
2.持久代(Perm)被写满
3.System.gc()被显示调用
4.上一次GC之后Heap的各域分配策略动态变化
3.3 Java有了GC同样会出现内存泄露问题
1.静态集合类像HashMap、Vector等的使用最容易出现内存泄露,这些静态变量的生命周期和应用程序一致,所有的对象Object也不能被释放,因为他们也将一直被Vector等应用着。
Static Vector v = new Vector();
for (int i = 1; i<100; i++)
{
Object o = new Object();
v.add(o);
o = null;
}
在这个例子中,代码栈中存在Vector 对象的引用 v 和 Object 对象的引用 o 。在 For 循环中,我们不断的生成新的对象,然后将其添加到 Vector 对象中,之后将 o 引用置空。问题是当 o 引用被置空后,如果发生 GC,我们创建的 Object 对象是否能够被 GC 回收呢?答案是否定的。因为, GC 在跟踪代码栈中的引用时,会发现 v 引用,而继续往下跟踪,就会发现 v 引用指向的内存空间中又存在指向 Object 对象的引用。也就是说尽管o 引用已经被置空,但是 Object 对象仍然存在其他的引用,是可以被访问到的,所以 GC 无法将其释放掉。如果在此循环之后, Object 对象对程序已经没有任何作用,那么我们就认为此 Java 程序发生了内存泄漏。
2.各种连接,数据库连接,网络连接,IO连接等没有显示调用close关闭,不被GC回收导致内存泄露。
3.监听器的使用,在释放对象的同时没有相应删除监听器的时候也可能导致内存泄露。
3.4GC 参考博客
https://www.cnblogs.com/sunniest/p/4575144.html
4.成员变量和局部变量
区别 | 成员变量 | 局部变量 |
---|---|---|
类中位置不同 | 类中方法外 | 方法内或者方法声明上(形参) |
内存中位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象的存在而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕而消失 |
初始化值不同 | 有默认的初始化值 | 没有默认的初始化值,必须先定义,赋值,才能使用 |
//1.在代码中的位置不一样,成员变量在类中方法外 局部变量在方法的内部或者方法的声明上
//2.成员变量有默认值,局部变量没有默认值,必须要先赋值,后使用
//3.在内存中位置不一样,成员变量在堆中,局部变量在栈中
//4.生命周期不一样, 成员变量的声明周期,随着对象的创建而存在,随着对象消失而消失,局部变量随着方法的压栈存在,随着方法的弹栈而消失
5.封装
5.1 private关键字
private关键字:
是一个权限修饰符
可以修饰成员(成员变量和成员方法)
被private修饰的成员只能在本类中才能访问
针对private修饰的成员变量,如果需要被其他类使用,提供相应的操作
提供“get变量名()”方法,用于获取成员变量的值,方法用public修饰
提供“set变量名(参数)”方法,用于设置成员变量的值,方法用public修饰
public class Student {
String name;
private int age;
//如果一个属性被private修饰,就表示这个属性私有化了,不能被外界使用
/*
java针对被private 修饰属性 提供了getXxx()和setXxx()方法用来取值或者赋值
setXxx()格式:
public void setXxx(成员变量的数据类型 变量名){
成员变量名 = 变量名
}
public 成员变量的数据类型 getXxx(){
return 成员变量名
}
*/
public void setAge(int a) {
if (a>0&&a<=120){
age = a;
}else {
System.out.println("您的年龄不合理!!!!!");
}
}
public int getAge(){
return age;
}
public void study() {
System.out.println("GOOD GOOD STUDY DAY DAY UP");
}
}
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "张三";
// stu.age = 1800;
stu.setAge(1800);
System.out.println(stu.name);
// System.out.println(stu.age);
int age = stu.getAge();
System.out.println(age);
stu.study();
}
}
5.2 this关键字
作用:
用来区分成员变量和局部变量
this代表对当前对象的引用,谁调用我,我就代表谁
什么是引用:对象在堆内存中的地址
public class Student {
String name;
private int age;
public void setAge(int age) {
if (age>0&&age<=120){
//age = age; //没有赋值成功的原因,应为Java中变量定义就近原则
this.age = age;// 解决方案:java给出了一个this关键字 ,用来区分成员变量和局部变量
}else {
System.out.println("您的年龄不合理!!!!!");
}
}
public int getAge(){
return age;
}
}
public class TestStudent {
public static void main(String[] args) {
Student stu = new Student();
stu.name = "张三";
System.out.println(stu.name);
stu.setAge(18);
int age = stu.getAge();
System.out.println(age);
Student stt = new Student();
stt.name = "李四";
System.out.println(stt.name);
stt.setAge(17);
int age1 = stt.getAge();
System.out.println(age1);
}
}
6.构造方法
/*
构造方法:
作用:
1.创建对象
2.初始化属性值
格式1:
public 类名(){ //无参构造方法,无参构造函数,无参构造器
}
格式2:
public 类名(参数列表){ //有参的构造方法,参数可以有一个,也可以有多个
......
}
构造方法的特点:
1.如果类中没有提供构造方法,JVM会提供一个默认无参构造方法
2.如果类中提供了构造方法,JVM就不会再通过默认无参构造方法
3.构造方法没有返回值,也不能使用void 修饰
4.构造方法可以重载
*/
public class TestStudent {
public static void main(String[] args) {
//创建学生类对象
//使用构造方法
Student student = new Student();
Student zs = new Student("张三");
Student ls = new Student(17);
Student wangwu = new Student("wangwu",17);
}
}
public class Student {
private String name;
private int age;
// private String address;
public Student(){
System.out.println("无参构造方法被调用");
}
public Student(String name){
System.out.println("有参构造方法被调用name");
this.name = name;
}
public Student(int age){
System.out.println("有参构造方法被调用age");
this.age = age;
}
/* public Student(String address){
this.address = address;
System.out.println("无参构造方法被调用");
}*/
public Student(String name,int age){
System.out.println("有参构造方法被调用name+age");
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
7.标准类的编写
成员变量
使用private修饰
构造方法
提供一个无参构造方法
提供一个带多个参数的构造方法
成员方法
提供每一个成员变量对应的setXxx()/getXxx()
提供一个显示对象信息的show()
创建对象并为其成员变量赋值的两种方式
无参构造方法创建对象后使用setXxx()赋值
使用带参构造方法直接创建带有属性值的对象
/*
类名要和文件名一模一样,符合大驼峰名规范,做到见名知义
成员变量,要用private关键字修饰 提供getXxx()和setXxx()方法
构造方法:提供两个构造方法,一个无参,一个满参
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
x()和setXxx()方法
构造方法:提供两个构造方法,一个无参,一个满参
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}