Java笔记_面向对象

类是一种自定义的数据类型,可以使用类来定义变量,而所有使用类定义的变量统称为 引用变量;所以说,所有类是引用类型。在面向对象的程序设计过程中,类和对象是很重要的两个概念,类用于描述客观世界里某一类对象的共同特征,而对象则是类的具体存在,如:人类和人

类和对象

定义类

[修饰符] class 类名 {
    成员变量(零到多个)... 
    构造方法(零到多个)...
    成员方法(零到多个)...
}

修饰符:public、final、abstract,或省略

类名:一个或多个单词,每个单词首字母大写,其它字母小写,单词与单词之间没有分隔符

成员变量:定义该类的实例所包含的状态数据

成员方法:定义该类或该类的实例行为特征或功能实现

构造函数:用于构造该类的实例,通过new关键字来调用,返回该类的实例 (构造函数是类创建对象的根本途径,没有则无法创建实例,如果编写类时没有编写构造函数,系统默认添加一个无参构造)

成员变量

[修饰符] 类型 成员变量名 [=默认值];

修饰符:可省略、【public、protected、private】(只能出现其一)、【static、final】(可以与前面的组合用)

类型:基本类型和引用类型

成员变量名:一个或多个单词,第一个单词首字母小写,之后的每个单词首字母大写,其余都小写,不要用分隔符

默认值:可选

成员方法

[修饰符] 方法返回值类型 方法名(形参列表){
    // 零条到多条可执行语句组成的方法体
}

修饰符:【public、protected、private】(只能出现其一)、【final、abstract】(只能出现其一)、static(可以与前面的组合用)

强调:static修饰的成员变量和方法称为类变量、类方法,属于类本身;不使用static修饰的成员变量和方法称为

实例变量、实例方法,属于该类的单个实例;静态成员不能直接访问非静态成员。

方法返回值类型:基本类型和引用类型

  1. 有返回值:方法体内必须有一个 return

  2. 无返回值:则返回值类型为 void

方法名:与成员变量的命令方式相同,建议以英文动词开头

形参列表:用于定义该方法可以接受的参数,多个参数以英文逗号隔开

格式: 参数类型 形参名

构造函数

[修饰符] 构造器名(形参列表){
    // 由零条到多条可执行语句组成的构造器执行体
}

修饰符:可省略、【public、protected、private】(只能出现其一)

构造器名:构造器名必须与类名相同

形参列表:和定义方法的形参列表的格式完全相同

实例

class Circle {
    // 定义成员变量
    double radius = 1;

    // 定义构造函数
    Circle(){
    }
    Circle(double newRadius){
        radius = newRadius;
    }

    // 定义成员方法
    double getArea(){
        return radius * radius * Math.PI;
    }
    double getPerimeter(){
        return 2 * radius * Math.PI;
    }
    void setRadius(double newRadius){
        radius = newRadius;
    }
}

对象的产生与使用

通过关键字 new 来调用某个类的构造函数即可创建这个类的实例。

代码形式(如调用Circle类)

Circle c = new Circle();

对象作用

1、访问对象的实例变量;如: c.radius

2、调用对象的方法;如: c.getArea();

Circle c = new Circle();在内存中做了哪些事情?

1)加载Circle.class文件进内存

2)在栈空间为 c 开辟空间

3)在堆内存为 Circle对象开辟空间

4)对Circle的成员变量进行默认初始化

5)对Circle的成员变量进行显示初始化

6)通过构造方法对circle对象的成员变量赋值

7)Circle对象初始化完毕,把对象地址赋值给c 变量

对象、引用和指针

解析: Circle c = new Circle();

new Circle() 创建了一个Circle对象,然后将该对象赋给c变量;因此该代码产生了一个对象和一个变量。

{% asset_img java20190329000.png %}

  1. 如果堆内存里的对象没有任何变量指向该对象,则程序无法访问该对象,该对象会被垃圾回收机制回收,释放该对象所占用内存。
  2. 如果想通知垃圾回收机制回收某个对象,则可以给引用变量赋值为null

对象的this引用

this关键字是指向调用对象本身的引用名(通俗讲:哪个对象调用this就代表谁)。

三种用法

this可以引用对象的实例成员。

class Circle {
    private double radius = 1;
    省略...
    public double getArea(){
        return this.radius * this.radius * Math.PI;
    }
    public String toString(){
        return "radius: " + this.radius + "area " + this.getArea();
    }
}

等价于

class Circle {
    private double radius = 1;
    省略...
    public double getArea(){
        return radius * radius * Math.PI;
    }
    public String toString(){
        return "radius: " + radius + "area " + getArea();
    }
}

形参与成员名字重名,用this来区分

class Person{
    private int age = 10;
    public Person(){
        System.out.println("初始化年龄: " + age);
    }
    public int setAge(int age){
        this.age = age;
        return this.age;
    }
}

引用构造函数

this(参数) :调用本类中另一种形式的构造函数(应该为构造函数的第一条语句)。

public class Circle{
    private double radius;
    public Circle(double radius){
        this.radius = radius;  //this关键字用于引用所构建的对象的隐藏数据域radius
    }
    public Circle(){
        this(1.0);  // this关键字用于调用另外一个构造方法
    }
}

成员变量和局部变量

成员变量和局部变量的区别

类中的位置不同

  1. 成员变量:类中方法外
  2. 局部变量:方法定义中或方法声明上

内存中的位置不同

  1. 成员变量:堆中
  2. 局部变量:栈中

生命周期不同

  1. 成员变量:随对象的创建而存在,随对象的消失而消失
  2. 局部变量:随方法的调用而存在,随着方法的调用完毕而消失

初始化值不同

  1. 成员变量:有默认值
  2. 局部变量:没有默认值,必须定义,赋值,然后才能使用

隐藏和封装

什么是封装

封装:指将对象状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该 类所提供的方法来时先对内部信息的操作和访问。

作用

  1. 隐藏类的实现细节
  2. 通过预先定义的方法访问数据,限制对成员变量的不合理访问
  3. 数据检查,完整性
  4. 便于修改

访问控制符

详细介绍

  • private(当前类访问权限): 成员只能在当前类的内部被访问。
  • default(包访问权限): 成员或外部类可以被相同包下的其它类访问。
  • protected(子类访问权限): 即可以被同一个包中其他类访问,也可以被不同包中的子类访问。
  • public(公共访问权限): 成员或外部类可以被所有类访问。

package、import和import static

package:文件夹

  • 作用:对类进行分类管理,方便组织自己的代码,将自己的代码与别人提供的代码库分开管理。确保类名的唯一性。
  • 定义格式: package 包名;
  • 包名命令规则:全部小写。(建议将公司域名倒过来写。如:com.baidu)

注意事项

  1. package语句必须是程序的第一条可执行的代码
  2. package语句在一个java文件中只能有一个
  3. 如果没有package,默认表示无名包

import:一个类可以使用所属包中的所有类,以及其它包中的共有类。

访问另一个包的共有类的两种方式

  1. 每个类名之前添加完整的包名:

    java.time.LocalDate today = java.time.LocalDate.now();
  2. 使用import语句导入一个特定的类或者整个包:

    import java.util.*;
    LocalDate today = LocalDate.now();

import static:
静态导入使用import static语句,分别用于导入指定类的单个静态成员变量、方法和全部静态成员变量、方法。

import 和 import static的作用
使用import可以省略写包名;而使用import static则可以连类名都可省略

java常用的包

  • java.lang:Java核心类。如String、Math、System等,无须用import导入,系统自动导入。
  • java.util:工具类/接口和集合框架类/接口,如Arrays和List、Set等。
  • java.net:网络编程相关的类/接口
  • java.io:输入/输出编程相关的类/接口
  • java.text:格式化相关的类
  • java.sql:JDBC数据库编程的相关类/接口

构造方法

作用: 用于创建实例时执行初始化。

格式

  1. 方法名与类名相同
  2. 没有返回值类型,连void都没有
  3. 没有具体的返回值

注意事项

  1. 如果不提供构造方法,系统会给出默认构造方法
  2. 如果提供了构造方法,系统讲不再提供
  3. 构造方法也可以重载

类的继承

概念

子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

格式

class 父类 {
}
class 子类 extends 父类{
}

为什么需要继承

没有继承的实例(代码重复,臃肿)

企鹅类:

public class Penguin {
    private String name;
    private int id;

    public Penguin(String name,int id){
        this.name = name;
        this.id = myid;
    }
    public void eat(){
        System.out.println(name + "在吃东西");
    }
    public void sleep(){
        System.out.println(name + "正在睡觉");
    }
}

老鼠类:

public class Mouse{
    private String name;
    private int id;

    public Mouse(String name,int id){
        this.name = name;
        this.id = id;
    }

    public void eat(){
        System.out.println(name + "在吃东西");
    }
    public void sleep(){
        System.out.println(name + "正在睡觉");
    }
}

有继承的实例 (简介、复用性好)

公共类:

public class Animal{
    private String name;
    private int id;

    public Penguin(String name,int id){
        this.name = name;
        this.id = myid;
    }

    public void eat(){
        System.out.println(name + "在吃东西");
    }
    public void sleep(){
        System.out.println(name + "正在睡觉");
    }
}

企鹅类:

public class Penguin extends Animal {
    public Penguin(String name,int id){
        super(name,id);
    }
}

老鼠类:

public class Mouse{
    public Mouse(String name,int id){
        super(name,id);
    }
}

继承类型

特性

  1. 子类拥有父类非private的属性、方法
  2. 子类可以对父类进行扩展
  3. 子类用自己的方式实现父类的方法 (重写)
  4. java只支持单继承,不支持多继承,但支持多层继承
  5. 提高了类之间的耦合性,代码独立性差

继承关键字

extends 和 implements

所有类都继承与 java.lang.Object

如果类没有继承关键字,则默认继承Object祖先类

示例:

extends关键字

public class Animal{
    private String name;
    private int id;

    public Animal(String name, int id){
        this.name = name;
        this.id = id;
    }

    public void eat(){}
    public void sleep(){}
}

implements关键字

使用implements关键字可以变相的使java具有多继承的特性

public interface A{
    public void eat();
    public void sleep();
}
public interface B{
    public void show();
}
public class C implements A,B{
}

super 与 this 关键字

  • this:代表当前对象的引用,谁来调用我,我就代表谁
  • super:代表当前对象父类的引用

区别

  1. 调用成员变量
    • this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
    • super.成员变量 调用父类的成员变量
  2. 调用构造方法
    • this(…) 调用本类的构造方法
    • super(…) 调用父类的构造方法
  3. 调用成员方法
    • this.成员方法 调用本类的成员方法,也可以调用父类的方法
    • super.成员方法 调用父类的成员方法

继承中构造方法的注意事项:
super(…)和this(…)必须出现在构造方法的第一条语句上

final

最终的意思,可以修饰类、成员变量、成员方法

特点

  • 修饰类,类不能被继承
  • 修饰变量,变量就变成了常量,只能被赋值一次
  • 修饰方法,方法不能被重写

Override/Overload

重载(Overload): 方法名相同,参数的数量不同或数量相同而类型和次序不同 (一个类的多态性表现)

重写(Override): 子类具有与父类相同名字,参数个数和类型一样,返回值也一样的方法(父类与子类的一种多态性表现)

多态

概述

多态是同一个行为具有多个不同表现形式或形态的能力。(通俗的讲,就是同一个事件发生在不同的对象上会产生不同的结果

多态存在的三个必要条件

  1. 要有继承或者实现关系
  2. 要有方法重写 (不是必须)
  3. 要有父类引用指向子类对象,如:Parent p = new Child();

示例:(成员变量、成员方法、静态方法、如果解决父类不能使用子类特有方法)

class Fu {
    public int num = 100;

    public void show() {
        System.out.println("show Fu");
    }

    public static void function() {
        System.out.println("function Fu");
    }
}

class Zi extends Fu {
    public int num = 1000;
    public int num2 = 200;

    public void show() {
        System.out.println("show Zi");
    }

    public void method() {
        System.out.println("method zi");
    }

    public static void function() {
        System.out.println("function Zi");
    }
}


class DuoTaiDemo {
    public static void main(String[] args) {

        Fu f = new Zi();
        System.out.println(f.num);   //100
        //找不到符号
        //System.out.println(f.num2);

        f.show();  // show Zi
        //找不到符号
        //f.method();
        f.function();    //function Fu
    }
}

多态中成员访问特点

  1. 成员变量

    编译看左边(父类),运行看左边(父类)

  2. 成员方法

    编译看左边(父类),运行看右边(子类)

  3. 静态方法

    编译看左边(父类),运行看左边(父类)

多态的优缺点

好处

  • 提高了程序的维护性(有继承保证)
  • 提高了程序的扩展性(由多态保证)

弊端

  • 不能访问子类特有功能

多态中的转型

向上转型

  • 由子到父
  • 父类引用指向子类对象

向下转型

  • 由父到子
  • 父类引用转为子类对象

初始化块

在java中,使用{}括起来的代码被称为代码块,根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程)

  1. 局部代码块

    在方法中出现,限定变量生命周期,及早释放,提高内存利用率

  2. 构造代码块

    在类中方法外出现,多个构造方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行。

  3. 静态代码块

    在类中方法外出现,并加上static修饰,用于给类进行初始化,在加载的时候就执行,并且执行一次

类成员

static关键字修饰的成员就是类成员,可以修饰成员变量、方法、初始化块、内部类;类成员属于整个类,而不属于单个对象。

特点:

  1. 随着类的加载而加载
  2. 优先于对象存在
  3. 被类的所有对象共享
  4. 可以通过类名调用

注意:如果有个成员被所有对象所共享,则它应该被定义成静态的

注意事项

  1. 在静态方法中没有this关键字
    • 静态是随着类的加载而加载的,this是随着对象的创建而存在的
    • 静态比对象先存在
  2. 静态方法只能访问静态的成员变量和静态的成员方法

静态变量和成员变量的区别

静态变量也叫类变量,成员变量也叫对象变量

  1. 所属不同
    • 静态变量属于类,成员变量属于对象
  2. 内存中位置不同
    • 静态变量存储于方法区的静态区,成员变量存储于堆内存中
  3. 内存出现时间不同
    • 静态变量随着类的加载而加载,随着类的消失而消失
    • 成员变量随着对象的创建而存在,随着对象的消失而消失
  4. 调用不同
    • 静态变量可以通过类名调用,也可以通过对象调用
    • 成员变量只能通过对象名调用

final修饰符

final关键字是最终的意思,可以修饰类、成员变量、成员方法。其中:

  • 修饰类:类不能被继承
  • 修饰变量:变量就变成了常量,只能被赋值一次
  • 修饰方法:方法不能被重写

final修饰基本类型变量和引用类型变量的区别:

基本类型:基本类型的值不能发生改变。

int x = 10;
x = 100;
System.out.println(x);
final int y = 10;
y = 100;  //无法为最终变量y分配值
System.out.println(y);  // 报错:Exception in thread "main" java.lang.Error: Unresolved compilation problem: The final local variable y cannot be assigned.

引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。

//局部变量是引用数据类型
Student s = new Student();
System.out.println(s.age);
s.age = 100;
System.out.println(s.age);
System.out.println("--------------");

final Student ss = new Student();
System.out.println(ss.age);
ss.age = 100;
System.out.println(ss.age);

//重新分配内存空间
//无法为最终变量ss分配值
ss = new Student();

抽象类

所有对象都是通过类来描绘的,如果一个类中没有包含足够的信息来描绘一个具体的对象,就把这种了类称为抽象类。

特点

  1. 抽象类和抽象方法必须用abstract关键字修饰
  2. 不能被实例化,只有抽象类的非抽象子类可以创建对象
  3. 抽象类不一定有抽象方法,但有抽象方法的类必定是抽象类
  4. 构造方法、类方法不能声明为抽象方法
  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类

格式:

abstract class 类名 {}
public abstract void 方法名();

abstract不能和哪些关键字共存

  • private 冲突
  • final 冲突
  • static 无意义

接口

概述

接口(Interface)是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。实现类通过继承接口的方式,从而来继承接口的抽象方法。

接口的声明

[修饰符] interface 接口名称 [extends 其他的接口名]{
    // 生命变量
    // 抽象方法
}

示例:

interface Animal{
    public void eat();
    public void sleep();
}

接口的使用

[修饰符] class 类名 extends 父类 implements 接口1, 接口2, ...{
    //类体部分
}

示例:

public class Cat implements Animal{
    public void eat(){
        System.out.println("cat eats");
    }
    public void travel(){
        System.out.println("cat sleep");
    }
    public int noOfLegs(){
        return 0;
    }
    public static void main(String[] args){
        Cat c = new Cat();
        c.eat();
        c.sleep();
    }
}

接口成员特点

  1. 成员变量

    只能是常量
    默认修饰符 public static final (只能是public,private会报编译错误)

  2. 构造方法

    没有,接口主要是扩展功能的,没有具体存在

  3. 成员方法

    只能是抽象方法
    默认修饰符 public static (只能是它,其他的会报错)

接口与类的区别

  1. 接口不能实例化对象
  2. 没有构造方法
  3. 所有的方法必须是抽象方法
  4. 支持多继承

抽象类和接口的区别:

抽象类:
    成员变量:可以变量,也可以常量
    构造方法:有
    成员方法:可以抽象,也可以非抽象
接口:
    成员变量:只可以常量
    成员方法:只可以抽象

类与类、类与接口、接口与接口之间的关系

类与类
    继承,单继承
类与接口
    实现,单实现,多实现
接口与接口
    继承,单继承,多继承

内部类

将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类分为以下四种:

成员内部类

最普通的内部类,定义在位于另一个类的内部,形式如下:

class Circle{
    double radius = 0;

    public Circle(double radius) {
        this.radius = radius;
    }

    class Draw {
        public void drawShape(){
            System.out.println("drawshape");
        }
    }
}

成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。

class Circle {
    private double radius = 0;
    public static int count = 1;
    public Circle(double radius) {
        this.radius = radius;
    }

    class Draw {
        public void drawShape(){
            System.out.println(radius);  //外部类的private成员
            System.out.println(count);  // 外部类的静态成员
        }
    }
}

注意:当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,访问形式如下:

  • 外部类.this.成员变量
  • 外部类.this.成员方法

内部类可以无条件访问外部类的成员,而外部类想访问成员内部类则必须先建一个内部类对象:

class Circle {
    private double radius = 0;

    public Circle(double radius) {
        this.radius = radius;
        getDrawInstance().drawShape();  //必须先创建成员内部类的对象,再进行访问
    }

    private Draw getDrawInstance() {
        return new Drwa();
    }

    class Draw {  // 内部类
        public void drawShape(){
            System.out.println("radius");  // 外部类的private成员
        }
    }
}

成员内部类是依附外部类而存在的,要创建成员内部类对象,前提是必须存在一个外部类的对象。

public class Test {
    public static void main(String[] args){
        //第一种方式
        Outrer outter = new Outer();
        Outter.Inner inner = outter.new Inner();  //  必须通过Outter对象来创建

        //第二种方式
        Outter.Inner inner1 = outter.getInnerInstance();
    }
}

class Outter {
    private Inner inner = null;
        public Outter(){
    }

    public Inner getInnerInstance(){
        if(inner == null){
            inner = new Inner();
        }
        return inner;
    }
    class Inner{
        public Inner(){
        }
    }
}

内部类可以拥有 private、protected、public 访问权限及包访问权限。由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。

局部内部类

定义在一个方法或者一个作用域里面的类,和成员内部类的区别在于局部内部类的范围内仅限于方法内或者该作用域内。

class People {
    public People(){
    }
}
    class Man {
        public Man(){
    }
    public People getWoman(){
        class Woman extends People {
            int age = 0;
        }
        return new Woman();
    }
}

注意:局部内部类和方法里面的一个局部变量一样,不能有public、protected、private以及static修饰符。

匿名内部类

适合创建只需要一次使用的类。创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。

定义格式

new 实现接口() | 父类构造器(实参列表){
    // 匿名内部类的类体部分
}

实例:

public interface Person {
    public void run();
}

public class Test {
    public static void main(String[] args){
        Person p = new Person() {
            public void run(){
                System.out.println("匿名内部类实现");
            }
        }
        p.run();
    }
}

使用规则

  1. 不能有构造方法,但是如果这个匿名内部类继承了一个只含有带参数构造方法的父类,在创建它的对象的时候,在括号中必须带上这些参数;
  2. 匿名内部类不可以定义任何静态成员和方法;
  3. 匿名内部类不可以被public、protected、private、static修饰;
  4. 只能创建匿名内部类的一个实例

静态内部类

定义在另一个类中且多加了一个static关键字的类。静态内部类不需要依赖外部类,且不能使用外部类的非static成员变量或方法(因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。

public class Test {
    public static void main(String[] args){
        Outter.Inner inner = new Outter.Inner();
    }
}

class Outter {
    int a = 10;
    static int b = 5;
    public Outter() {
    }

    static class Inner {
        public Inner(){
            System.out.println(a);  // 报错:无法从静态上下文中引用非静态变量a
            System.out.println(b);
        }
    }
}
-------------本文结束感谢您的阅读-------------
Mr.wj wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!