Java面向对象

这篇博客详细介绍了Java的面向对象编程,包括面向对象的概念、类与对象的创建、构造方法、初始化顺序、对象内存分析、封装、继承、super的使用、多态、instanceof和类型转换、static关键字、抽象类、接口的定义与实现、内部类及其应用场景。
摘要由CSDN通过智能技术生成

面向对象

面向对象01:什么是面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)
  • 面向对象的本质:以类的方式组织代码,以对象的组织(封装)数据
  • 面向对象具有抽象、封装、继承、多态等特性
  • 认识角度:先有对象后有类。对象是具体的事物。类是抽象的,是对对象的抽象
  • 代码运行角度:先有类后有对象,类是对象的模板
  • 将复杂的业务逻辑简单化,增强代码复用性

面向对象02:回顾方法的定义和调用

public class Demo01 {
  //main方法
  public static void main(String[] args) {
    
  }
  //static修饰的方法与类一同加载
  public static void a() {
    b();//报错,非静态方法在类实例化后才可经对象调用
  }
  private void b(){}
}
public class Demo02 {
  //引用传递
  public static void main(String[] args) {
    Person person = new Person();
    System.out.println(person.name);//null
    Demo02.change(person);
    System.out.println(person.name);//sss
  }
  
  public static void change(Person person) {
    //person是一个指向类的对象
    person.name = "sss";
  }
  
	static class Person {
  	String name;
	}
}

面向对象03:类与对象的创建

在Java中万事万物都是对象。尽管一切都是对象,但是可操纵都是一个对象的引用。有一个对象引用,但不一定需要一个对象与之关联

Car carKey;//一个对象引用

这里创建的只是引用,而并非对象,但是如果你想要使用carKey这个引用时,会返回一个异常,告诉你需要一个对象来和这个引用进行关联。一种安全的做法是,在创建对象引用时同时把一个对象赋给它。

Car carKey = new Car();
  • 使用new关键字创建对象
  • 使用new关键字创建的同时,除了分配内存空间外,还会给创建好的对象进行默认的初始化即对类中构造器的调用。
  • 类中的构造器也称构造方法,是在创建对象时必须调用的,具有以下特点:
    • 方法名与类名相同
    • 无返回类型,也不能写void类型

IDEA :alt+insert 快捷创建构造方法

IDEA : 在 Project Structure 中添加out目录查看class文件

构造方法

  • 在Java中的一种特殊的方法,也被称为构造函数、构造器等。在Java中通过提供这个构造器来确保每个对象都被初始化。构造方法只能在对象的创建时期调用一次。
public class Person {
  //一个类什么都不写也会存在默认构造方法
  String name;
  
  //无参构造
  public Person() {
    this.name = "null";
  }
  //有参构造
  public Person(String name) {
    this.name = name;
  }
  
  //new实例化一个对象,本质调用构造方法
  Person person = new Person("zz");
}

初始化顺序

  • 静态属性:static开头定义的属性
  • 静态方法快:static {} 包含的代码块
  • 普通属性:非static定义的属性
  • 普通方法快:{} 包起来的代码块
  • 构造函数:类名相同的方法
  • 方法:普通方法
public class LifeCycle {
  //静态属性
  private static String staticField = getStaticField();
  //静态方法快
  static {
    System.out.println(staticField);
    System.out.println("静态方法块初始化");
  }
  //普通属性
  private String field = getField();
  //普通方法快
  {
    System.out.println(field);
  }
  //构造函数
  public LifeCycle() {
    System.out.println("构造函数初始化");
  }
  //静态方法
  public static String getField() {
    String field = "Field Initial";
    return field;
  }
  //主函数
  public static void main(String[] args) {
    new LifeCycle();
  }
}

面向对象04:创建对象内存分析

  • 堆中存放具体创建的对象
  • 栈中存放方法和应用变量名
  • 方法区加载类的模板

在这里插入图片描述

面向对象05:小结

  1. 类是一个模板,一个抽象。对象是一个具体的实例

  2. 方法:定义和调用

  3. 除八大基本类型外都是引用类型,对象是通过引用来操作的:栈—>堆

  4. 属性:字段(Field) 成员变量

    默认初始化:

    ​ 数字:0 0.0

    ​ char:u0000

    ​ boolean:false

    ​ 引用:null

    修饰符 属性类型 属性名 = 属性值

  5. 对象的创建和使用

    • 必须使用new关键字创建对象,同时调用构造器
    • 对象的属性
    • 对象的方法
  6. 类包含:

    静态的属性

    动态的方法

面向对象06 :封装

  • 封装又称为访问控制权限,它是面向对象三大特性中的一种

  • 访问控制权限的核心:只对需要的类可见

  • 类中私有属性通过get/set方法操作

  • Java中成员的访问权限共有四种,分别是**private、protected、public、default:

可见性privatedefaultprotectedpublic
同一类
同一包中的类
子类
其他包中的类

alt + insert 自动生成get/set方法

隐藏类的属性,通过操作接口来访问

  • 提高程序安全性
  • 隐藏代码的实现细节
  • 统一接口
  • 增加可维护性

面向对象07:什么是继承

  • 继承是所有面向对象语言不可或缺的部分。在Java中只要我们创建了一个类,就隐式的继承Object父类

  • Java只有单继承,没有多继承。一个子类只能有一个直接父类,一个父类可以有多个子类。但存在间接继承。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zd9m1C4t-1656386563746)(C:\Users\16339\AppData\Roaming\Typora\typora-user-images\image-20220628094402266.png)]

  • 继承的关键字是extends,如上图,如果使用了extends显示指定了继承,Father即为父类,Son即是子类
class Father{}

class Son extends Father{}

继承双方拥有某种共性的特征

class Father {
  public void feature() {
    System.out.println("父类的特征");
  }
}

Class Son extends Father {
  //若Son没有重写feature方法,则默认用的是父类的feature方法
}

面向对象08:Super详解

  • super访问父类的属性和方法
public class Student extends Person {
  private String name = "zhang";
  
  public Student() {
    //隐藏的代码:调用父类的构造方法:super()
    //调用父类构造方法必须写在子类构造方法的第一行
    //this.()调用本类的构造,不可与super()同时调用构造方法
    super();
    System.out.println("子类构造");
  }
}
  • 创建对象时先调用父类构造器,默认调用无参构造器

  • super调用父类的构造方法,必须在构造方法的第一个

  • super必须只能出现在子类的方法或构造方法中

  • super和this不能同时调用构造方法

  • this()调用本类的构造

  • super()调用父类的构造

面向对象09:方法的重写

重写需要有继承关系,子类重写父类的方法

  • 方法名相同
  • 参数列表必须相同
  • 修饰符:范围可以扩大但不能缩小:public>protected>default>private
  • 抛出的异常:范围可以被缩小,但不能扩大:ClassNotFoundException–>Exception(错误)
  • 重写,子类的方法和父类必须要一致,方法体不同
public class B {
    public void test() {
          System.out.println("B->test()");
    }
}

public class A extends B {
    public void test() {
          System.out.println("A->test()");
    }
}

public class Test {
  //只可重写非静态方法
  public static void main(String[] args) {
   	 //方法的调用只与左边定义的数据类型有关
   	 //父类引用指向子类
    	B a = new A();
    	a.test(); //A->test()
  	}
}

面向对象10:什么是多态

  • 多态是方法的多态,属性没有多态

  • 实现多态的三个充要条件:

    • 继承

    • 重写父类方法

    • 父类引用指向子类

    • father s1 = new Son();

  • 不可重写的方法:

    • static静态方法不属于实例对象,属于类,不可被重写

    • final 修饰的方法

    • private方法

public class Fruit {
  	int num;
  
  	public void eat() {
    	System.out.println("eat fruit");
  	}
}

public class Apple extends Fruit {
  @Override
  	public void eat() {
      	super.num = 10;
      	System.out.println("eat" + num + "Apple");
  	}
  
    public static void main(String[] args) {
      	Fruit fruit = new Apple();
      	fruit.eat();//调用子类方法
    }
}
  • mian方法中,Fruit类型的对象指向了Apple对象的引用,这其实就是多态-> 父类引用指向子类对象,因为Apple继承于Fruit,并且重写了eat方法,所以能够表现出来多种状态的形式。

组合

  • 组合就是将对象引用置于新类中即可。组合也是一种提高类的复用性的一种方式。如果想让类有更多的扩展功能,多用组合,少用继承
public class SoccerPlayer {
  	private String name;
  	private Soccer soccer;
}

public class Soccer {
  	private String soccerName;
}
  • 代码中SoccerPlayer引用了Soccer类,通过引用Soccer类来达到调用soccer中属性和方法的目的

  • 组合和继承的区别主要如下:

特征组合继承
关系组合是一种has-a的关系,可理解为有一个继承是一种is-a的关系,可理解为是一个
耦合性组合的双方是一种耦合关系继承双方紧耦合
是否具有多态不具备多态和向上转型继承是多态的基础,可实现向上转型
时期组合是运行时绑定继承是编译期绑定

面向对象11:instanceof 和 类型转换

  • instanceof 是 Java 的一个二元操作符,类似于 ==,>,< 等操作符。

  • instanceof 是 Java 的保留关键字。它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。

import java.util.ArrayList;
import java.util.Vector;
 
public class Main {
 
public static void main(String[] args) {
   Object testObject = new ArrayList();
      displayObjectClass(testObject);
   }
   public static void displayObjectClass(Object o) {
      if (o instanceof Vector)
      System.out.println("对象是 java.util.Vector 类的实例");
      else if (o instanceof ArrayList)
      System.out.println("对象是 java.util.ArrayList 类的实例");
      else
      System.out.println("对象是 " + o.getClass() + " 类的实例");
   }
}
//结果:对象是 java.util.ArrayList 类的实例
  • 类型转换
//父类:Person 子类:Student
Person obj = new Student();
//父类转换为子类
Student student = (Student)obj;
student.go();

//子类转换为父类,可能丢失自己本来的一些方法
Student students = (Student)obj;
Person objs = students;
//go方法可能丢失
objs.go();
  • 父类引用指向子类的对象
  • 子类转换为父类,向上转型
  • 父类转换为子类,向下转型,强制转换
  • 方便代码利用率,减少类的创建

面向对象12:static关键字详解

public class Student {

    private static int age;//静态的变量  多线程
    private double score; //非静态的变量

    public void run() {
        go();//非静态方法可以调用静态方法
    }

    public static void go() {
        //run();//静态方法只能调用静态方法
    }

    public static void main(String[] args) {
        go();
        //run();
    }
}
  • 代码块
public class Person {

        {
            System.out.println("匿名代码块");
        }

        static {
            System.out.println("静态代码块");
        }

        public Person() {
            System.out.println("构造方法");
        }

    public static void main(String[] args) {
        Person s1 = new Person();
    }

}
/* 结果:
		静态代码块
		匿名代码块
		构造方法
*/
  • 静态导入包
//静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;

public class Test {

    public static void main(String[] args) {
        System.out.println(random());//直接使用random()方法
        System.out.println(PI);
    }

}

面向对象13:抽象类

  • abstract 定义抽象类和抽象方法,被子类单继承实现抽象方法

  • 抽象方法必须放在抽象类中

    抽象类中可以没有抽象方法

    抽象方法只定义无方法体

    一个类有大于等于一个抽象方法就是抽象类

  • 子类继承抽象类必须重写抽象方法

  • 抽象类不能new出对象

//abstract 抽象类: 单继承
//接口可以多继承
public abstract class Ab {
    //约束方法,让子类实现方法
    public abstract void doSomething();
    public void sum() {
    }
}
//子类继承抽象类
public class Bc extends Ab{
    @Override
    public void doSomething() {

    }
}

面向对象14:接口的定义和实现

接口相当于是对外的一种约定和标准,Java中接口是由interface关键字来表示的,可以在内部定义方法,但不实现,接口方法隐式修饰为public abstract

//定义接口
public interface Job{
 	 void fun();
}

接口特征:

  • interface接口是一个完全抽象的类,不会提供任何方法的实现,只会进行方法的定义
  • 接口中只能使用两种访问修饰符,一种是public,对整个项目可见。一种是default,缺省值,只具有包访问权限
  • 接口只提供方法的定义,由实现接口的类来提供方法的实现。实现接口关键字为implement,一个接口可以有多个实现,一个类可以实现多个接口
  • 实现类必须重写接口中的方法
class ZCZWriteWell implements Job {
  	@Override
  	public void fun() {
      	System.out.println("well");
    }
}

接口默认方法

  • 在接口中新增方法,意味着要在实现类中实现新增方法
  • 而默认方法可以直接在接口中实现:
public interface Job{
 	 	void fun();
  	//默认方法,接口实现类可以不在重写该方法
  	default void go() {
      	System.out.println("default method");
    }
}

面向对象15:内部类

内部类就是在一个类的内部定义另一个类,在A中类定义B类,B类就是A类的内部类,相对的,A类就是B类的外部类。

成员内部类

内部类定义在外部类成员的位置

总结

  • 内部类直接调用了外部类成员方法,原因是内部类拥有外部类对象的引用。

    方式:外部类名.this

  • 因此内部类可以直接访问外部类成员变量

public class FirstOuterClass {

    //成员内部类,定义的位置处于外部类成员的位置
    private class InnerClass {

        public void run() {
            //内部类拥有外部类对象的引用
            //所以可以直接使用外部类的成员
            System.out.println(FirstOuterClass.this);
        }

    }

    //外部类的非静态方法创建内部类对象
    public InnerClass getInnerClassObj() {
        return new InnerClass();
    }

    public static void main(String[] args) {
        //创建外部类对象
        FirstOuterClass firstOuterClass = new FirstOuterClass();
        //1.外部类的非静态方法构造内部类
        InnerClass innerClassObj = firstOuterClass.getInnerClassObj();
        System.out.println(innerClassObj);

        //2.借助外部类对象构造内部类
        InnerClass innerClass = firstOuterClass.new InnerClass();
        System.out.println(innerClass);

        System.out.println(firstOuterClass);
        innerClassObj.run();

    }
}

成员内部类应用场景

  • 为了隐藏并控制对这个类的访问
  • 为了将一个类定义在另一个类的内部:当一个类依托另一类存在时
  • 借助内部类实现多继承,内外部类都继承不同的类

静态内部类

  • 成员内部类使用static修饰即静态内部类
  1. 静态内部类不能访问外部类中的非静态成员
  2. 静态内部类不依赖外部类对象存在,无法拥有外部类对象的引用,构造一个静态内部类无需外部类来构造
  3. 静态内部类中可以有静态成员,成员内部类不能有静态成员
  • 创建一个静态内部类对象语法:new 外部类名.静态内部类名();
public class FirstOuterClass4 {

    private int a = 0;
    //静态成员
    private static int b = 1;

    //静态内部类
    public static class FirstInnerClass {

        public FirstInnerClass() {
            System.out.println(b);
        }

    }

  	//返回内部类对象
    public FirstInnerClass getFirstInnerClassObj() {
        return new FirstInnerClass();
    }

    public static void main(String[] args) {
        //直接构造静态内部类对象
        FirstInnerClass firstInnerClass1 = new FirstInnerClass();
        //创建一个外部类对象
        FirstOuterClass4 firstOuterClass4 = new FirstOuterClass4();
        FirstInnerClass firstInnerClass2 = firstOuterClass4.getFirstInnerClassObj();
    }
}

应用场景

  • 当一个类是另一个类(外部类)的附属类,它不依赖外部类对象而存在,并且需要单独在外部类之外使用,此时可以创建为静态内部类。

局部内部类

  • 定义在局部代码块或方法
  • 只能在局部作用域内new出局部内部类的对象
  • 特点:
  • 局部内部类只能在其作用域中被实例化,不能用外部类对象实例化一个局部内部类对象。
  • 局部内部类不能去使用public、private,因为局部内部类不是外部类的成员
  • 局部内部类可以访问外部类对象的成员、拥有外部类对象的引用

在封闭范围内(局部内部类)使用这个范围外的局部变量只能使用常量。

注意:局部内部类中可以去定义局部变量,如果要使用它之外的局部变量,此时编译器按照final类型处理。

  • 产生此限制的原因:

    由于局部变量和局部内部类生命周期不同,所以编译器统一要求,如果局部内部类使用了它之外的局部变量,此时编译器按照final处理

public class FirstOuterClass2 {
    
    //定义一个外部类的成员方法
    public void getFirstInnerClassObj() {

        int a = 1;
        //定义局部内部类,不可使用public、private修饰
        class FirstInnerClass {
        
            //构造方法
            public FirstInnerClass() {
                //得到外部类对象的引用
                System.out.println("外部类对象的引用"+FirstOuterClass2.this);
                System.out.println(a+1);
            }

            //普通方法
            public FirstInnerClass getInstance() {
                return this;
            }
        }

        //不能使用外部类对象构造局部内部类对象
        //只能在局部内部类的作用域中new出一个局部内部类对象
        FirstInnerClass firstInnerClass = new FirstInnerClass();
        FirstInnerClass innerClass = firstInnerClass.getInstance();
        System.out.println("局部内部类对象的引用" + innerClass);
    }

    public static void main(String[] args) {
        //构造一个外部类对象
        FirstOuterClass2 firstOuterClass2 = new FirstOuterClass2();
        firstOuterClass2.getFirstInnerClassObj();
    }
}
/* 结果
外部类对象的引用com.pbteach.javase.oop.innerclass.FirstOuterClass2@1b6d3586
2
局部内部类对象的引用com.pbteach.javase.oop.innerclass.FirstOuterClass2$1FirstInnerClass@4554617c
*/

匿名内部类

  • 匿名内部类是一种特殊的局部内部类,没有名字。
  • 定义格式:
new 父类或接口(){
	//写类的成员
	//重写父类或接口中的方法
};
  • 特点:
    • 没有名字
    • 特殊的局部内部类,不能使用private、public等权限修饰
    • 由于没有名字,不能定义构造方法,但可使用构造代码块实现构造方法的功能
    • 无法通过外部类对象进行实例化,可以访问外部类对象的引用
    • 匿名内部类要么继承一个父类,要么实现一个接口,两者不能兼备
    • 匿名内部类可以访问外部类对象的成员
    • 只允许使用他之外的final常量
   //成员内部类
  class FirstInnerClass {
      //构造方法
      public FirstInnerClass() {
        System.out.println("外部类对象的引用" + FirstOuterClass3.this);
      }
      //普通方法
      public FirstInnerClass getInstance() {
        return this;
      }	
  }
	//定义匿名内部类,是FirstInnerClass的子类
  FirstInnerClass firstInnerClass = new FirstInnerClass() {
      @Override
      public FirstInnerClass getInstance() {
        System.out.println("匿名内部类");
        System.out.println(this);
        return this;
      }
  };
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值