基础系列【四】-- 面向对象
面向对象思想
当前主流的编程语言主要分为两个大阵营,一个是面向对象编程,一个是面向过程编程。
面向过程和面向对象
面向过程:让计算机有步骤的做一件事,是一种过程化的叙事思维,
面向过程相对来说结构比较松散,强调如何流程化地解决问题。
面向对象:是一种计算机世界,解决复杂软件工程的方法论,从人类思维角度提出解决问题的步骤和方案。面向对象的思维更加内聚,强调高内聚,低耦合,先抽象模型,定义公共行为,再解决实际问题。
面向对象的顶级父类Object哲学
-
我是谁?getClass()方法说明其本质。
-
我从哪里来?Object构造方法是生产对象的基本步骤,Clone()是繁殖的另一种形式。
-
世界是否因我不同?hashCode()和equals()方法
-
我要怎样与别人协作?wait()和notify()是对象之间通信与协作的一种方法。
-
我要到哪里去?finalize()方法是在对象销毁时触发。
注意: JDK9之后,finalize方法已被标记为过时。 而wait和notify。已经被同步信号。所。阻塞集合取代。
我所理解的面向对象?
- 面向对象时一种软件编程思想。在现实生活中,人们把客观存在的事物称之为对象。我们所说的java是一种面向对象语言。在java中,我们有一句话叫做"万物皆对象"。在java中我们用面向对象来解决问题。
- 一般来说我们习惯解决问题的方式有:面向过程和面向对象。
1. 什么是面向过程?所谓过程即解决问题的步骤,它关注点事在于“步骤“,其特点是了解每个步骤中的每个细节。
1. 举个例子:你想要喝小米粥,你要去买粥(什么样的,去哪里买),之后淘米(用什么水掏,掏几遍),煮粥(怎么煮,煮多长时间等等),每个步骤都需要你去干,每个细节都需要你了解。
2. 什么是面向对象?面向对象关注点在于对象,我们只要找到一个合适的对象,我们就能够有用这个对象的属性和行为。
1. 举个例子:你到餐厅吃饭,我只要找一个厨师(我要找的对象),我就能达到我想要目的。- 面向过程和面向对象的区别和联系。
1. 都是解决问题的一种方法。面向过程–应用在简单场景,面向对象–应用在复杂场景。- 面向对象的特性:
1. 封装
2. 继承
3. 多态
4. (抽象)
类与对象的关系
- 类–一类个体。对象的概括/抽取/模板
- 个体–对象。
1. 我们把一类个体共有的特征抽取出来,作为类的属性。将个体共有的行为抽取为类的方法。可以说类是对个体的一种概括,对象时类的一个实例。
构造方法和构造代码块和局部代码块
- 构造代码块:定义在类中,在创建对象先于构造函数执行,在创建对象完成之后,完成初始一些初始化操作。–提高的代码的复用。
- 局部代码块:定义在方法中的代码块,限制局部变量的声明周期,提高内存的使用率。
匿名对象
- 只在堆内存中有对象而在栈内存中没有引用
- 匿名对象在创建者之后只能使用一次、
- 匿名对象可以作为参数传递
权限修饰
1. 注意:类中用,和类对象用一样吗?
这段代码有什么问题?protected 和默认修饰词
package cn.tedu.test1;
public class A {
int i ; //1–默认的访问权限修饰符:本类–同包类–
同包子类
protected void ma(){
System.out.println(“A ma”);
}
}
package cn.tedu.test2;
import cn.tedu.test1.A;
public class B extends A{
public void mb(){
super.i = 5; //2此处有错误–因为不是同包子类
}
}
package cn.tedu.test2;
import cn.tedu.test1.A;
public class C {
public static void main(String[] args){
A a = new A();
a.ma(); //3 此处有错误,protected访问权限修饰符,本类-子类用-同包类用
B b = new B();
b.mb(); //4
}
}
封装
- 封装的表现形式:函数,属性私有化,内部类。(行为封装,类封装)
- 封装的作用:提高代码的复用性,提高代码的安全性(指的是数据属性的合理性)
继承
- 将子类共有的属性和行为抽取出来,形成父类。
- 使用关键字extends继承父类
- 继承的特点:单继承(可以多重继承),只有单一父类。但一个父类可有多个子类。
- 单继承和多继承的区别?
1. 多继承-允许有个多个父类。代码复用性较高,但是当不同的父类中有相同的方法时,就会产生调用混乱。
2. 单继承–提高代码复用,和数据安全(这里指的是调用的明确性)- 在什么情况下父类中的东西不能继承过来?private 修饰的属性,构造函数,构造代码块
方法的重载
- 同一个类中–方法名相同,参数列表不同的方法,与返回值类型和修饰符无关。
- 静态方法和final修饰的方法都可以重载。
方法的重写
- 发生在继承关系中,父子类中。
- 遵循“两同两小一大”原则
1. 两同:方法名和参数列表相同。
2. 两小:
1. 返回值类型为基本类型,void,最终方法时,必须相同。其他要求子类的返回类型需小于等于父类。
2. 子类可抛出的异常小于等于父类
3. 一大:子类的访问权限修饰符必须大于等于父类。- 注意方法签名相同的方法并不一定是重写(静态方法们不能重写,但是可允许父子类中存在方法签名相同的静态方法。),但方法的重写,方法签名一定相同。
- 调用的时候,静态方法的执行看的是声明类
多态
- 多态:多种形态。是运行过程中动态绑定代码的行为。
- 根据多态出现的时期分为;
1. 编译期多态:方法的重载
2. 运行期多态:方法的重写,向上造型。
3. 类型判断:
1. instanceOf:判断两个类型之间是否可以转化
2. getClass:获取对象的实际运行类型
static
- 修饰变量:
- 修饰方法:由static修饰的方法,也叫类方法。静态方法随着类加载而加载到方法区的静态区,只将静态方法的信息保存到内存中,而不执行
- 静态方法先于对象而存在,可以不通过对象调用。
4 修饰代码块
5 修饰内部类
public class StaticDemo2 {
@SuppressWarnings("static-access")
public static void main(String[] args) {
// B.m();
// 重写是一种运行时多态,多态行为针对的是对象
// 静态不依附于对象,也因此针对对象的操作对静态无效。
// 多态:在编译或者运行时期动态绑定执行代码的行为---不同对象动态的绑定不同行为
// 对于静态而言与类绑定而不与对象绑定
// 对于静态方法不存在重写,但是允许父子类中存在方法签名一致的静态方法
// 并且在调用的时候,静态方法的执行看的是声明类
A a = new B();
a.m2();
a.m();
}
}
class A {
public static void m() {
System.out.println("A m()");
}
public static void m(int i) {
System.out.println("A m(int)");
}
public void m2() {
System.out.println("A m2()");
}
}
class B extends A {
public static void m() {
System.out.println("B m()");
}
@Override // 注解---@Override用于标识这个方法是一个重写的方法
public void m2() {
System.out.println("B m2()");
}
}
public class StaticDemo3 {
//静态块里面只能使用静态变量
//static final == final static 没有区别
//静态的东西只能定义成类属性
//除了静态内部类之外可以定义静态属性,其他类不能定义静态属性,但是可以定义常量
//在方法中不能或者静态块中不能定义静态属性。
//但是可以使用常量
//静态块内的东西直接执行
//静态方法不调用不执行。
//内部类不使用不执行
//类的静态属性在加载类的时候加载。类只加载一次,所以静态的属性只加载一次。
//类加载顺序 静态属性(加载到方法区,静态属性有初值,静态方法只提供模板,不调用不执行。)--构造代码块-构造函数(给类成员变量赋初值。)
final static int a ;
static {
a = 5;
System.out.println(a);
System.out.println("Demo static ");
System.out.println("静态块");
}
public static void main(String[] args) {
System.out.println(a);
SDemo.m();
new SDemo();
new SDemo();
}
}
class SDemo {
int i = 10;
// 在整个过程中,只在类加载的时候到栈内存中执行一次
static {
m();
System.out.println("static");
}
{
System.out.println("code");
}
public SDemo() {
System.out.println("constructor");
}
public static final void m(){}
}
public class StaticDemo4 {
public static void main(String[] args) {
// 在创建一个子类对象---必然要先创建一个父类对象 --- SA()
// 无论是创建SA对象还是SB对象,SA类和SB类都得加载---意味着SA和SB中的静态代码块都要执行
// 先加载A类再加载B类---然后先创建A对象再创建B对象
new SB();
System.out.println("==========================");
// 此时无需加载A和B两个类,意味着static修饰的属性和代码块就不会再初始化或者执行了
new SB();
/*
* A 1 C B 1 C D A 2 C A 3 B 2 B 3 ========================== C D A 2 C
* A 3 B 2 B 3
*/
}
}
class SA {
static SC c; // null
SD d = new SD();
static {
System.out.println("A 1");
}
{
System.out.println("A 2");
}
public SA() {
c = new SC();
System.out.println("A 3");
}
}
class SB extends SA {
static SC c = new SC();
static {
System.out.println("B 1");
}
{
System.out.println("B 2");
}
public SB() {
System.out.println("B 3");
}
}
class SC {
public SC() {
System.out.println("C");
}
}
class SD extends SC {
public SD() {
System.out.println("D");
}
}
final
修饰数据:修饰数据,被修饰的数据的值要求不可变–常量。
1.对于基本类型而言,指的是实际值不可变,对于引用类型而言,指的是地址不可变。而对象的属性值依然可以改变。
2.注意点:类似数组扩容和复制隐含的地址的改变
修饰方法
- final修饰方法–最终方法(不能被重写)。
- final修饰的方法能不能被继承?–可以被继承,但不能被重写
- final修饰的方法可以被重载–对于重载而言和修饰符没有任何关系,也跟返回值类型没关系,之和方法名和参数列表有关。
- 修饰类 1. 最终类–不能被继承 1.可以有父类吗?–可以
2.最终类的方法可以重写吗?–不可以,重写的前提是产生继承关系–父子类关系。
package day09final;
public class FinalDemo1 {
public static void main(String[] args) {
final int i = 5;
// *i++;final修饰的成员变量,值不可变
System.out.println(i);
changeValue(i);
int j = 8;
print(j);
}
// 每个变量在不同的方法中有不同的“身份”
public static void print(final int j) {// final int j = j--8
System.out.println(j);
}
public static int changeValue(int i) {
i++;
System.out.println(i);
return i;
}
}
package day09final;
import java.util.Arrays;
public class finalDemo2 {
public static void main(String[] args) {
// final 修饰的数据不可变,此时final修饰的是数组的地址----arr的地址不能变。
final int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
// 地址改变--不可以
/* arr = new int[4]; */
// arr[3] = 10;地址变了吗?--没变
arr[3] = 10;
//arr可以作为参数传递到changeRef中吗?---可以
//arr在主函数中定义为了常量,在changeRef中定义了常量了吗?--没有
//原来的arr地址没有变
changeRef(arr);
}
public static void changeRef(int[] arr){
//数组的复制和扩容--实际上是创建一个新数组
arr = Arrays.copyOf(arr, 2*arr.length);
}
}
package day09final;
public class FinalDemo4 {
}
class Demo {
final int i = 4;
// 没给初始化
/* final int j; */
// 对于成员变量属性而言,一旦声明为常量,必须在创建对象之前给值。
final int j;
//static随类加载,只加载一次。fianl:不可变。
//static final --真正意义的常量,只有一份。
static final int k /*= 7*/;//静态常量:可先给值,也可在类加载完成之前给值即可。
static{
k = 6;
}
{
/* j=5; */
}
public Demo() {
j = 5;
}
}
package day09final;
public class FinalDemo {
final int i;//这个常量i在对象完成之前给值即可。
/*{
this.i = 5;
}*/
public FinalDemo(){
this(5);
}
public FinalDemo(int i){
this.i = i;//构造代码块先执行,给i赋值为5,此代码试图改变i的值。--不可以
}
}
package day09final;
public class FinalDemo5 {
public static void main(String[] args) {
/*B b = new B();
b.m();*/
}
}
final class A extends Object{//可以继承
//最终方法,依然可被继承,但不能被重写
public final void m(){
System.out.println("A m");
}
//final的修饰的方法可以重载
public final void m(int i){
System.out.println("A m(int i)");
}
//static final 修饰方法?--看有没有冲突?--static 修饰的方法只能加载一次,final修饰不能被重写。没矛盾
public static final void mb(){
}
}
/*class B extends A{//不能被继承
}*/
static final总结
- //final 常量在初始化之前给值即可。
//final 修饰的数据表明数据的值不可变–基本类型值不可变,引用类型地址不可变,但是引用指向的对象可变。
//final 修饰的方法,可以被继承,可以被重载,不能被重写。
//final 修饰的类不能被继承。可以继承别的类。
//final/satatic 可以修饰构造方法吗?不能,仅仅有public protected 默认 private 可以修饰方法。- //静态块里面只能使用静态变量
//static final == final static 没有区别
//静态的东西只能定义成类属性
//除了静态内部类之外可以定义静态属性,其他类不能定义静态属性,但是可以定义常量
//在方法中不能或者静态块中不能定义静态属性。
//但是可以使用常量
//静态块内的东西直接执行
//静态方法不调用不执行。
//内部类不使用不执行
//类的静态属性在加载类的时候加载。类只加载一次,所以静态的属性只加载一次。
//类加载顺序 静态属性(加载到方法区,静态属性有初值,静态方法只提供模板,不调用不执行。)–构造代码块-构造函数(给类成员变量赋初值。)
abstract
- 如果不同的子类对父类中的某个方法m做了不同程度的重写,那么这个时候父类中的m方法在提供方法体就没有意义,就可以省略不写,把这个方法省生明为抽象方法,由abstract修饰的方法为抽象方法。
- 含有抽象方法的类必须为抽象类。
- 抽象类的特点和继承关系
1. 抽象类不能创建实例对象,但是可以使用抽象类创建内部类。
1. 抽象类不能创建对象–有构造方法吗?–有--不能用Java语言创建抽象类的对象,若一个类继承抽象类时,在创建子类对象时,父类对象由JVM创建
2. 一个类继承了抽象类,必须重写抽象类中的所有的抽象方法,或者子类也声明为抽象类。
3. 抽象类可以不包含抽象方法
1. 抽象方法可以重载吗?–可以,方法的重载和修饰符无关。
2. 抽象方法可以用static/final/private修饰吗?–不能
4. 如果抽象方法时默认权限修饰符,对子类有什么要求?–子类和抽象类必须同包
4. 抽象类本身也是一个类,所有普通类中允许定义的属性和方法在抽象类中都可以定义。
1. 抽象类可以用final修饰吗?–不能—抽象类可能存在抽象方法,抽象方法必须被重新,重写的前提是产生继承,final修饰的类不能被继承。
2. 抽象(任何)类中的构造函数可以是私有的吗?–可以
package day10;
public class AbstactDemo {
public static void main(String[] args) {
// 抽象类,不允许创建实例对象。
// 这是因为类中存在抽象方法, ,则可以通过对象调用类中的抽象方法,抽象方法没有方法体,不能运行。
// 在java中每个类在编译完成之后对应一个class文件
// Shape s = new Shape(3,5) {//匿名内部类
// @Override
// public double getGirth() {
// // TODO Auto-generated method stub
// return 0;
// }
//
// @Override
// public double getArea() {
// // TODO Auto-generated method stub
// return 0;
// }
// };
}
}
// 定义一个类,提供矩形,圆形,并求周长和面积
abstract class Shape {
private double x;
private double y;
public Shape(double x, double y) {
super();
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public void setX(double x) {
this.x = x;
}
public double getY() {
return y;
}
public void setY(double y) {
this.y = y;
}
// 由于子类对该方法的实现都不同,父类的方法给上方法体没有实际意义,仅仅作为标识这个方法可以允许扩展
// 只提供方法的模板,不提供方法的具体实现,用abstract修饰的方法叫抽象方法。
// 含有抽象方法的类,必须为抽象类。
public abstract double getGirth();
public abstract double getArea();
}
// 如果一个类继承了一个抽象类,子类中必须重写抽象类的所有抽象方法或者子类也声明为抽象方法
class Rectangle extends Shape {
public Rectangle(double x, double y) {
super(x, y);
}
@Override
public double getGirth() {
return 2 * (this.getX() + this.getY());
}
@Override
public double getArea() {
return this.getX() * this.getY();
}
}
接口
- 定义接口的关键字–interface,定义接口
- 接口内的所有方法都为抽象方法(JDK1.7及其以前)
- 在(JDK1.8之后)接口中可以定义普通方法
B b = new C();
// 将父类对象赋值给子类对象,需要进行强转
// 检查b对象的声明类和c对象的声明类之间是否有继承关系
// b的声明类是B,而c的声明类是C类,C继承了B,所以编译通过
// 运行的时候,会检查b的实际类型,b的创建类型是C,C对象的声明类型也是C,所以类型匹配,允许强转
C c = © b;
// 将父类对象强转为子类对象的时候,编译不报错,但是运行的时候如果实际类型不匹配,会出现ClassCastException
// b的声明类为B,d的声明类为D,D继承了B,所以编译通过
// 运行的时候,发现b的实际类型为C,D的声明类型为D,C没有继承D,C和D的类型就不匹配,所以运行的时候报错
// D d = (D) b;
// 在对对象进行强转的时候,会检查前后两个对象的声明类之间是否有继承关系。
// 如果有继承关系,则编译通过,但是运行的时候会再检查实际类型是否匹配
// 如果没有继承关系,则编译失败
// c的声明类型为C,d的声明类型为D,C和D之间没有继承关系,所以编译就不通过
// D d = (D)c;
// 因为在Java中类之间支持的单继承,所以对于一个类而言,是容易确定这个类的父类的
// 由于接口与接口之间是多继承且类和接口之间是多实现,因此形成一张继承结构网,不容易确定接口和接口之间的关系以及类和接口的关系
// 因此为了提高编译效率,在编译的时候JVM放弃检查接口和类之间的关系
// 所以在编译的时候任何一个对象都可以强转为一个接口对象,仅限于在编译的时候不报错
// 而运行的时候检查这个类和当前的接口是否有实现关系
内部类
- 定义在类中的类–内部类
1. 内部类:根据类的定义位置分为
1. 方法内部类:定义在方法中的类–局部内部类
2. 成员内部类–定义在类中方法的外边
3. 静态内部类–用static修饰的内部类
4. 匿名内部类–如果一个类只用一次,可以用匿名内部类。
方法内部类
package day10;
import java.io.Serializable;
public class InnerClass {
public static void main(String[] args) {
Outer1 out = new Outer1();
out.m();
}
}
class Outer1 {
int o = 0;
public void m() {
// 显示声明
final int k = 10;
System.out.println("Outer1 m");
// 次类定义在方法中--方法内部内/局部内部类
// 只能在此方法的内部使用
// 方法内部类中可以定义成员变量或者成员方法
// 方法内部类中不能定义静态属性或者静态方法,但是可以声明静态常量
// 方法内部类使用当前方法中的数据的时候,要求这个数据是一个常量
// 在JDK1.8中允许方法内部类来使用当前方法中的隐式常量
// 方法内部类可以使用外部类的一切属性和方法
class Inner1 extends Object implements Serializable {
int i = 5;
static final int j = 4;
// static int j = 7;
/*
* static void m1() { // The method m1 cannot be declared static;
* static methods can // only be declared in a static or top level
* type }
*/
public void m() {
System.out.println("Inner1 m");
System.out.println(k); // Cannot refer to the non-final local
System.out.println(o); // variable k defined in an enclosing scope
}
}
Inner1 inner1 = new Inner1();
inner1.m();
}
}
成员内部类
package day10;
public class InnerDemo2 {
public static void main(String[] args) {
Outer2 out = new Outer2();
System.out.println(out.k);
/* out.m(); */
// 创建内部类对象
Outer2.Inner2 inner2 = new Outer2().new Inner2();
inner2.m();
}
}
class Outer2 {
int k = 0;
// 成员内部类,可以把内部类当成外部类的成员方法
// 成员内部类中可以定义成员变量和成员方法
// 成员内部类中不能声明静态变量和静态方法,但是可以使用静态常量
// 成员内部类中可以使用外部类的一切成员属性和方法
// 成员内部类可以用任何修饰符来修饰
class Inner2 {
int i = 5;
int k = 8;
static final int j = 0;
public void m() {
System.out.println(this);
System.out.println("Inner2 m");
System.out.println(this.k);// 8
System.out.println(Outer2.this.k);// 0
}
}
public void m() {
Inner2 inner2 = new Inner2();
inner2.m();
}
}
静态内部类--用static修饰的内部类
package day10;
public class StaticInnerDemo3 {
public static void main(String[] args) {
//表示调用Outer3外部类的Inner3内部类的静态方法
Outer3.Inner3.ms();
//表示调用Outer3外部类的Inner3内部类的非静态方法
Outer3.Inner3 oi = new Outer3.Inner3();
oi.m();
}
}
class Outer3{
int i = 3;
//静态内部类
//静态内部类中可以定义成员变量和成员方法,也可以定义静态变量和静态方法。
//静态内部中只能使用外部内中的静态属性
static class Inner3{
static boolean b = false;
double d = 2.3;
public void m(){
//System.out.println(i);//Cannot make a static reference to the non-static field i
System.out.println(1);
}
public static void ms(){
System.out.println(b);
}
}
}
匿名内部类--如果一个类只用一次,可以用匿名内部类。
package day10;
public class InnerDemo4 {
//如果匿名内部类定义在方法外==成员内部类
B b = new B(){
};
public static void main(String[] args) {
//匿名内部类
//匿名内部类实质指的是{}内的内容
//a实际上指的是匿名内部类所处创建的对象
//匿名内部类本质上是继承了对应的类或者是实现了对应的接口
//任何接口或者抽象类都可以有都可以有内部类形式
//任何类只要可以被继承,那就可以存在匿名内部类--最终类不能产生匿名内部类
AB a = new AB(){
};
}
}
class C{
C c = new C(){
};
//构造函数私有化,并不代表该类不能被继承。还有内部类。
private C(){
}
class D extends C{
}
}
class B{
}
abstract class AB{
}
内部类总结
3.总结:在java中类中可以定义类,类中可以定义接口(默认是静态的),接口中可以定义类(默认是静态的),接口中可以定义接口(默认是静态的)
类的访问权限修饰符:public protected 默认 private final abstract static
外部类的权限修饰符有public(同一个文件中只能有一个public类),final,abstract修饰
成员内部类当类:可以用以上修饰符修饰;
当类属性:成员方法,可以定义成员属性或者方法,能调用外部类的静态成员。但内部成员内部类中不能声明静态属性。
局部内部类(方法内部类只有):abstract和final可以修饰:局部内部类相当于方法的"局部变量",仅在本方法里可用。局部变量访问权限修饰符有final。
局部内部类:相当于类的成员变量或者成员方法(静态属性只有类能声明),和类的非静态属性同级,在成员内部类中能调用外部类的静态成员。但内部成员内部类中不能声明静态属性。
匿名内部类:所有的修饰符都可以用:匿名内部类相当于类的成员变量,类变量所有的访问权限修饰符都可以用。
匿名内部类==成员内部类
静态内部类:当类的属性:相当于类中的静态块,只能使用外部类的静态成员。
包
- 声明包用package–必须写在java第一行,而且java中只能有一个package(可有可无),包声明的多级结构(cn.tedu.inner)
- import.java.util.–表示导入了util包下的所有的类,但是不包括util包下的子包中的类;–称之为通配符。
- 导包语句import—如果我需要用的类和当前类不在同一个包下,则需要导包。
- java.lang–包含了一个java程序运行的基本类,这个包下的所有类直接都在程序启动的时候自动加载到方法区中了,所以在这个包下的所有类可以直接类,不需要导包。
- java.util–工具包–提供了一系列操作对象的方法和类
- java.applet–小应用程序有关–单独的窗口。可以内嵌到网页中
- java.awt–图形界面
- java.io–数据传输
- java.math–和数字和数学运算有关
- java.net–和网络通信有关的包
- java.nio–高并发(大量对象同时引入)
- java.security–数据安全
- java.sql–和数据进行交互的包
- java.text–格式化有关的包
- javax–是java包的扩展包
- org–第三方厂商提供的常见功能
垃圾分代回收机制
1.栈内存:计算–(执行方法或者代码块–方法本身带有名字的代码块)–栈内存用完就释放。
2.方法区:存储类的信息(类的类名,成员变量-成员方法,静态变量-静态方法(静态区))–只加载一次,只进不出。
3.堆内存:
- 垃圾回收机制针对的是堆内存。
1.在java中每个对象在使用完成之后,并不是立即移除出对内存的。会有GC(Garbage Collection)在不定的某个时刻被回收的。在一个程序启动的时候,GC就已经启动了,GC会实时监控对内存的状态,在对内存达临界点(0.75)的时候,会启动gc来回收堆内存的无用对象。
2.gc的使用有堆内存的确定,但我们可以调用Ststem.gc();来建议gc快点来收堆内存的垃圾。但是gc不一定来。
3. 堆内存:新生代和老生代 1. 新生代 1.伊甸园区
4.幸存区
5.伊甸园:幸存区内存比例 4:1- 新创建的对象会方法园区。经过一次回收扫描,如果这个对象没有被使用,则会回收。若仍在使用,会将对象挪到幸存区。若果在多次扫描,发现该对象没有被使用,则会被回收。若该对象仍在使用,则会将该对象移至老年代。老年代的扫描频率远远小于新生代的扫描频率。老生代的对象一般来说都比较重要,假如老生代的对象背回收,则可能发生卡顿,甚至程序崩溃。
3.发生在新生代的回收–初代回收(minor gc)
4.发生在老生代的回收–完全回收(full gc)
5.注意:一个对象刚创建的时候放到伊甸园区,如果这个对象需要的内存比较大而新生代提供的内存又不够用的时候,会将该对象放入老生代。如果老生代也不够用会抛出错误。OutOfMemoryError;
总结
面向对象对开发者来讲可分为三个过程:
1.OOA:面向对象分析
2.OOD:面向对象设计
3.OOP:面向对象编程
在现实生活中我们任何物体都可以归为一类事物,而每一个个体都是一个事物的实例子,我理解面向对象是面向世界万物的一种归纳和演绎方法。
前者是从具体到本质,从个性到共性,将一类对象的共同特征进行归一化的逻辑思维过程(类)。后者是从本质到具体从共性到个性逐步形象化的过程(实例)。
在实际开发中,我们通常根据名词来寻找对象,动词来确定对象的方法。对象从概念上可以说是一种责任的的集合体,从规格上讲是一系列可以被自己或者其它对象调用的方法,从实现上讲是一堆程序和数据。
下一篇:
基础系列【六】–String