面向对象总结

1. 面向对象和面向过程的区别

面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象:就是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。

2. 对象和类

2.1 对象

万物皆对象:
软件系统所模拟的真实世界中,所有的实体都可以抽象为对象
每个对象都是唯一的
对象具有属性和行为(方法)
对象具有状态:
状态指某个瞬间对象各种属性的取值
对象的方法可以改变对象自身的状态
对象都属于某个类,每个对象都是某个类的实例

2.2 类

类是一组具有相同属性和行为的对象的抽象
开发人员自定义数据类型
面向对象编程的主要任务就是定义各个类
对象是类的实例,类是对象的模板

类的认识重点介绍类和对象的基本定义,属性和方法的基本使用方式。
属性(field 成员变量)
属性用于定义该类或该类对象包含的数据或者说静态特征。属性作用范围是整个类体。
在定义成员变量时可以对其初始化,如果不对其初始化,Java使用默认的值对其初始化。

数据类型默认值
整型0
浮点型0.0
字符型‘\u0000’
布尔型false
所有引用类型null

属性定义格式:

[修饰符]  属性类型  属性名 = [默认值] ;

方法
方法用于定义该类或该类实例的行为特征和功能实现。方法是类和对象行为特征的抽象。方法很类似于面向过程中的函数。面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
方法定义格式:

[修饰符]  方法返回值类型  方法名(形参列表) {
	// n条语句
}

【示例】类的定义方式

// 每一个源文件必须有且只有一个public class,并且类名和文件名保持一致!
public class Car { 
}
class Tyre { // 一个Java文件可以同时定义多个class
}
class Engine {
}
class Seat {
}

上面的类定义好后,没有任何的其他信息,就跟我们拿到一张张图纸,但是纸上没有任何信息,这是一个空类,没有任何实际意义。所以,我们需要定义类的具体信息。对于一个类来说,一般有三种常见的成员:属性field、方法method、构造器constructor。这三种成员都可以定义零个或多个。

【示例】编写简单的学生类

public class SxtStu {
    //属性(成员变量)
	int id;
	String sname;
	int age;	
	//方法
	void study(){
		System.out.println("我正在学习!");
	}	
	//构造方法
 	SxtStu(){
 	}
}

2.3 this关键字

2.3.1 对象创建的过程和this的本质

构造方法是创建Java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回该类的对象,但这个对象并不是完全由构造器负责创建。创建一个对象分为如下四步:
(1)分配对象空间,并将对象成员变量初始化为0或空
(2)执行属性值的显式初始化
(3)执行构造方法
(4)返回对象的地址给相关的变量
this的本质就是“创建好的对象的地址”! 由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象”。

2.3.2 代码实现

this普通用法:

public class User {
	int id;		//id
	String name;	//账户名
	String pwd; 	//密码
	public User() {
	}
	public User(int id, String name) {
		System.out.println("正在初始化已经创建好的对象:"+this);
		this.id = id;   //不写this,无法区分局部变量id和成员变量id
		this.name = name;
	}
	public void login(){
		System.out.println(this.name+",要登录!");  //不写this效果一样
	}	
	public static void main(String[ ] args) {
		User  u3 = new User(101,"张三");
		System.out.println("打印张三对象:"+u3);
		u3.login();
	}
}

this()调用重载构造方法

public class TestThis {
	int a, b, c;
	TestThis() {
		System.out.println("正要初始化一个Hello对象");
	}
	TestThis(int a, int b) {
		// TestThis(); //这样是无法调用构造方法的!
		this(); // 调用无参的构造方法,并且必须位于第一行!
		a = a;// 这里都是指的局部变量而不是成员变量
// 这样就区分了成员变量和局部变量. 这种情况占了this使用情况大多数!
		this.a = a;
		this.b = b;
	}
	TestThis(int a, int b, int c) {
		this(a, b); // 调用带参的构造方法,并且必须位于第一行!
		this.c = c;
	}
	void sing() {
	}
	void eat() {
		this.sing(); // 调用本类中的sing();
		System.out.println("你妈妈喊你回家吃饭!");
	}
	public static void main(String[ ] args) {
		TestThis hi = new TestThis(2, 3);
		hi.eat();
	}
}

2.4 static 关键字

2.4.1 static特点

在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效。它有如下特点:
(1)为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
(2)对于该类的所有对象来说,static成员变量只有一份。被该类的所有对象共享!!
(3)一般用“类名.类属性/方法”来调用。(也可以通过对象引用或类名(不需要实例 化)访问静态成员。)
(4)在static方法中不可直接访问非static的成员。

2.4.2 代码实现

package test;

public class User2 {
    private  int id;
    private String name;
    private  String pwd;
    private static String company="北京烤鸭";

    public User2(int id, String name) {
        this.id = id;
        this.name = name;
    }
     public void login(){
         System.out.println(name+"已登录");
     }
     public static void showCompany(){
       // login();调用非静态成员,编译报错
         //System.out.println(id);
         System.out.println(company);
     }

    public static void main(String[] args) {
        User2 user2 = new User2(123,"张三");
        user2.login();
        //User2.login();无法使用类名调用非静态成员
        //User2.id;
        User2.showCompany();
        User2.company="羊蝎子";
        User2.showCompany();
    }
}

张三已登录
北京烤鸭
羊蝎子

2.5 包机制

package在java中的作用类似于“操作系统中文件夹的作用”。主要解决两个问题:
(1)提供多层的命名空间,解决命名冲突;(处于不同package中的类可以拥有相同的名字)
(2)对类按功能进行分类,使得项目的组织更加清楚

JDK中的主要包
在这里插入图片描述
导入类import
如果我们要使用其他包的类,需要使用import导入,从而可以在本类中直接通过类名来调用,否则就需要书写类的完整包名和类名。import后,便于编写代码,提高可维护性。

注意要点
(1)Java会默认导入java.lang包下所有的类,因此这些类我们可以直接使用。
(2)如果导入两个同名的类,只能用包名+类名来显示调用相关类:
java.util.Date date  = new  java.util.Date();

3. 面向对象三大特征

3.1 封装(encapsulation)

3.1.1 封装的作用

隐藏对象的属性和实现细节,仅仅对外公开接口。
编程中封装的具体优点:
(1)提高代码的安全性。
(2)提高代码的复用性。
(3)“高内聚”:封装细节,便于修改内部代码,提高可维护性。
(4)“低耦合”:简化外部调用,便于调用者使用,便于扩展和协作。

3.1.2 封装的使用

Java是使用“访问控制符”来控制哪些细节需要封装,哪些细节需要暴露的。 java提供四种访问权限控制符,如下表:
在这里插入图片描述
注意:在继承中(继承在下面会详细介绍):
(1)若子类与父类在同一个包中,子类可以访问父类的protected成员,也可以访问父类对象的protected成员。
(2)若子类与父类不在同一个包中,子类可以访问父类的protected成员,但不可以访问父类对象的protected成员。(即,能用继承来的protected成员,但不能通过new 父类对象来调用protected成员)。

3.1.3 javaBean封装

package com.sxt.test;

public class TestEncapsulate {
private int id;
private String name;
private boolean man;

public TestEncapsulate() {
}

public TestEncapsulate(int id, String name, boolean man) {
this.id = id;
this.name = name;
this.man = man;
}

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public boolean isMan() {
    return man;
}

public void setMan(boolean man) {
    this.man = man;
}

}

3.2 继承:(extends)

3.2.1 继承的要点

(1)父类也称作超类、基类、派生类等。
(2)Java中只有单继承,没有像C++那样的多继承。多继承会引起混乱,使得继承链过于复杂,系统难于维护。
(3)Java中类没有多继承,接口有多继承。
(4)子类继承父类,可以得到父类的全部属性和方法 (除了父类的构造方法),但不见得可以直接访问(比如,父 类私有的属性和方法)。
(5)如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object。

3.2.2 继承的实现

(1)方法重写(override)
方法的重写需要符合下面的三个要点:
a.“= =”: 方法名、形参列表相同。
b.“≤”:返回值类型和声明异常类型,子类小于等于父类。
b.“≥”: 访问权限,子类大于等于父类。
(2)代码实现


public class Animal {
    public  void shout(){
        System.out.println("叫一声");
    }

}
class Dog extends Animal{
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}
class Cat extends Animal{
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}

注意:
继承的层次不可太多,尽量两到三层;继承的最上层最好抽象

3.2.3 final 关键字

final关键字的作用:
(1)修饰变量: 被他修饰的变量不可改变。一旦赋了初值,就不能被重新赋值。
final int MAX_SPEED = 120;
(2)修饰方法:该方法不可被子类重写。但是可以被重载!
final void study(){}
(3)修饰类: 修饰的类不能被继承。比如:Math、String等。
final class A {}

3.2.4 组合

我们可以通过继承方便的复用已经定义类的代码。还有一种方式,也可以方便的实现“代码复用”,那就是:“组合”。
“组合”不同于继承,更加灵活。
“组合”的核心就是“将父类对象作为子类的属性”,然后,“子类通过调用这个属性来获得父类的属性和方法”。
示例如下:

public class Test{
    public static void main(String[ ] args) {
        Student s = new Student("高淇",172,"Java");
        s.person.rest();      //s.rest();
        s.study();
    }
}
class Person {
    String name;
    int height;
    public void rest(){
        System.out.println("休息一会!");
    }
}
class Student /*extends Person*/ {
    Person person = new Person();
    String major; //专业
    public Student(String name,int height,String major) {
        //天然拥有父类的属性
        this.person.name = name;      //this.name = name;
        this.person.height = height;      //this.height = height;
        this.person.rest();
        this.major = major;
    }
}

3.3 多态(polymorphism)

3.3.1 多态的要点

a.多态是方法的多态,不是属性的多态(多态与属性无关)。
b. 多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象。
c. 父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了。

3.3.2 对象转型

父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换。
向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要进行类型的强制转换,我们称之为向下转型!

3.3.3 instanceof关键字

instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false。

3.3.4代码实现

public class Animal {
    public  void shout(){
        System.out.println("叫一声");
    }

}
class Dog extends Animal{
    @Override
    public void shout() {
        System.out.println("汪汪汪");
    }
}
class Cat extends Animal{
    @Override
    public void shout() {
        System.out.println("喵喵喵");
    }
}

class TestExtends{
    public static void main(String[] args) {
        Animal a = new Dog();
        a.shout();

        if (a instanceof Dog){
            Dog d1 = (Dog) a;
            a.shout();
        }
        if (a instanceof Cat){
            Cat c1 = (Cat) a;
            c1.shout();
        }

    }
}

4.抽象类(abstract)

4.1 抽象方法和抽象类

抽象方法:使用abstract修饰的方法,没有方法体,只有声明。定义的是一种“规范”,就是告诉子类必须要给抽象方法提供具体的实现。
抽象类:包含抽象方法的类就是抽象类。通过abstract方法定义规范,然后要求子类必须定义具体实现。通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。

4.2使用要点

(1)有抽象方法的类只能定义成抽象类
(2)抽象类不能实例化,即不能用new来实例化抽象类。
(3)抽象类可以包含属性、方法、构造方法。但是构造方法不能用来new实例,只能用 来被子类调用。
(4)抽象类只能用来被继承。
(5)抽象方法必须被子类实现。

4.3代码实现

//抽象类
abstract class Animal {
	abstract public void shout();  //抽象方法
}
class Dog extends Animal {	
	//子类必须实现父类的抽象方法,否则编译错误
	public void shout() {
		System.out.println("汪汪汪!");
	}
	public void seeDoor(){
		System.out.println("看门中....");
	}
}
//测试抽象类
public class TestAbstractClass {
	public static void main(String[ ] args) {
		Dog a = new Dog();
		a.shout();
		a.seeDoor();
	}
}

5.接口(interface)

5.1接口作用

接口就是比“抽象类”还“抽象”的“抽象类”,可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。
抽象类还提供某些具体实现,接口不提供任何实现,接口中所有方法都是抽象方法。接口是完全面向规范的,规定了一批类具有的公共方法规范。

5.2 声明

声明格式:

[访问修饰符]  interface 接口名   [extends  父接口1,父接口2…]  {
常量定义;	
方法定义;
}

定义接口的详细说明:
(1)访问修饰符:只能是public或默认。
(2)接口名:和类名采用相同命名机制。
(3)extends:接口可以多继承。
(4)常量:接口中的属性只能是常量,总是:public static final 修饰。不写也是。
(5)方法:接口中的方法只能是:public abstract。 省略的话,也是public abstract。

5.3代码实现

 class TestInterface{
     public static void main(String[] args) {
         Volant volant = new Angel();
         volant.fly();    //Angel类只实现了Volant接口的fly(),不能调用Angel类中实现Honest的helpOther()
         Honest h= (Honest) volant;//要想调用,需要强转成Honest,这样编译才能通过
         h.helpOther();
         System.out.println(Volant.FLY_HIGHT);
         Honest h2= new GoodMan();
         h2.helpOther();
         Volant v2= new SuperMan();
         v2.fly();

     }
}


//飞行接口
interface Volant {
    public static final int FLY_HIGHT =100;
    void fly();
}

//善良接口
interface Honest{
    void helpOther();
}
class Angel implements Volant,Honest{

    @Override
    public void fly() {
        System.out.println("我是天使,会飞");
    }

    @Override
    public void helpOther() {
        System.out.println("我是天使,很善良,正在扶老奶奶过马路");
    }
}
class GoodMan implements Honest{

    @Override
    public void helpOther() {
        System.out.println("我是一个好人,正在铲奸除恶");
    }
}
class SuperMan implements Volant{

    @Override
    public void fly() {
        System.out.println("我是超人,我会飞");
    }
}

5.4 默认方法和静态方法

JAVA8之前,接口里的方法要求全部是抽象方法。
JAVA8(含8)之后,以后允许在接口里定义默认方法和类方法。

public interface A {
    default void moren(){
        System.out.println("我是接口A中的默认方法");
    }
    static void jingtai(){
        System.out.println("我是接口A中的静态方法");
    }
}
class Test_A implements A{
    @Override
    public void moren() {
        System.out.println("我是实现类中重写的默认方法");
    }
    void jingtai(){
        System.out.println("我是子类里面的静态方法(不是重写[静态方法不能重写],是新方法)");
    }

    public static void main(String[] args) {
        A a= new Test_A();
        a.moren();
        Test_A t1= (Test_A) a;
        t1.jingtai();
        A.jingtai();
    }
}

5.5接口的多继承

interface A {
	void testa();
}
interface B {
	void testb();
}
/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
	void testc();
}
public class Test implements C {
	public void testc() {
}
	public void testa() {
	}
	public void testb() {
	}
}

6.垃圾回收机制(Garbage Collection)

Java引入了垃圾回收机制,令C++程序员最头疼的内存管理问题迎刃而解。Java程序员可以将更多的精力放到业务逻辑上而不是内存管理工作上,大大的提高了开发效率。
分代垃圾回收机制,是基于这样一个事实:不同的对象的生命周期是不一样的。因此,不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。同时,将处于不同状态的对象放到堆中不同的区域。 JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。

  1. 年轻代
    所有新生成的对象首先都是放在Eden区。 年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。
  2. 年老代
    在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。
  3. 永久代
    用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。JDK7以前就是“方法区”的一种实现。JDK8以后已经没有“永久代”了,使用metaspace元数据空间和堆替代。

图 堆内存的划分细节
在这里插入图片描述
(1)Minor GC:用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1”、“Survivor2”区中。
(2)Major GC:用于清理老年代区域。
(3)Full GC:用于清理年轻代、年老代区域。 成本较高,会对系统性能产生影响。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值