7.面向对象

面向对象

初识面向对象

  • 面向对象本质:以类的方式组织代码,以对象的方式组织(封装)数据;

方法回顾与加深

方法定义

/*
修饰符	返回值类型	方法名(...) throws 异常{
	//方法体
	return 返回值;
}
*/
  • 修饰符:
    • 四种权限修饰符:public 、 protected 、 default 、 private
    • static:static属性和方法都可以直接通过类名调用,只执行一次,且每一个类所有对象共享同一个static属性/方法;
    • final:常量,不能被继承;
  • 返回类型:
  • break和return区别:
    • break:结束循环或者switch语句
    • return:结束方法,返回一个值(可以无返回值)
  • 方法名:
  • 参数列表:
  • 异常抛出:

方法调用

  • 静态方法:可以直接通过类名.方法名调用;和类同时加载,属于类;
public static void main(String[] args){
    int sum = add(1,2);//在同一个类中可省略类名调用
    System.out.println(sum);
    //输出3
}
public static int add(int a, int b){
    return a+b;
}
  • 非静态方法:需要先new一个对象,才能使用对象名.方法名调用;需要new对象和才加载,属于对象;
public class Demo01{
    public static void main(String[] args){
    	Demo02 demo02 = new Demo02();
    	int sum = demo02.add(1,2);
        System.out.println(sum);
        //输出3
	}
}

class Demo02{
    public int add(int a, int b){
    	return a+b;
	}
}
  • 形参和实参:

    • 形参:上述代码中add方法定义时int a,int b,其中a,b就是形参;
    • 实参:上述代码中调用add方法时传入的1,2就是实参;
  • 值传递和引用传递:

    • java中全部是值传递,值传递就是将1,2这两个值复制一份给a,b分别赋值,修改形参的值并不会影响形参的值;

    • 引用传递就是将内存中存放实参的内存地址传给了形参,从而修改形参的值实际上也会修改实参的值;传递对象时和引用传递相似:

      public class Demo03 {
          public static void main(String[] args) {
              Person person = new Person();
              //只是创建了一个对象,并未给对象赋值,所以person.name = null;
              System.out.println(person.name);
      
              //调用reName方法后,将整个对象的地址传递给reName方法
              reName(person);
              System.out.println(person.name);
          }
          public static void reName(Person person){
              //实质上这个person对象,指向的是 Person person = new Person();具体的对象,修改这里同时修改了实参中的数据
              person.name = "刀刀木";
          }
      }
      class Person{
          String name;
      }
      /*
      null
      刀刀木
      */
      
  • this关键字:用来调用本类中成员变量,参照下一节代码;


对象创建分析

  • 类是一种抽象的数据类型,是对某一类事物整体描述/定义,包括该类事物应具备的特点和行为,但是并不代表某一个具体事物;
public class Student {
    //属性:字段
    String name;
    int age;

    //方法
    public void study(){
        System.out.println(this.name+"在学习");
    }
}

构造器

  • 也就是构造方法;
  • 方法名和类名相同;
  • 未定义时每个类都有一个默认的构造方法;
  • 构造方法可以不止一个,方法重载;
  • 必须没有返回值类型,且不能定义void返回值类型;
  • 实例化初始值,new对象时实质上是在调用构造方法;
  • 一旦定义了有参构造,必须定义无参构造,
public class Person(){
    String name;
    public Person(){//无参构造,一般定义了有参构造之后无参构造内容常为空
		this.name = "小明";    
	}
    public Person(String name){//有参构造
        this.name = name;
    }
}
//快捷键 Alt+insert自动生成构造器

对象

  • 对象是类的具体实例;
public class Application {
    public static void main(String[] args) {
        //实例化类
        //类实例化后会返回一个自己的具体对象
        Student xiaoMing = new Student();
        Student xiaoHong = new Student();

        System.out.println(xiaoMing.name);
        System.out.println(xiaoMing.age);

        xiaoMing.name = "小明";
        xiaoMing.age = 3;

        System.out.println(xiaoMing.name);
        System.out.println(xiaoMing.age);

    }
}
/*
null
0
小明
3
*/

创建对象内存分析

public class Application {
    public static void main(String[] args) {
        Pet dog = new Pet();
        dog.name = "旺财";
        dog.age = 3;
        dog.shout();

        Pet cat = new Pet();
        
    }
}
//输出:旺财叫了一声
//在两个文件中,一个文件中只有一个类可用public修饰
public class Pet {
    public String name;
    public int age;

    public void shout(){
        System.out.println(this.name+"叫了一声");
    }
}
  • 大致内存分析如下:

在这里插入图片描述


面向对象三大特性

封装(数据的隐藏)

  • 应禁止直接访问一个对象中数据的实际表示,而应通过接口来访问;
  • 高内聚,低耦合
    • 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
    • 低耦合:仅暴露少量的方法给外部使用;
  • 封装多对于属性而言,属性私有;
  • 作用:
    • 提高程序的安全性,保护数据;
    • 隐藏代码的实现细节;
    • 统一接口;
    • 系统可维护性增强;
public class Application {
    public static void main(String[] args) {
        Student xiaoMing = new Student();

        xiaoMing.setName("小明");
        System.out.println(xiaoMing.getName());
        xiaoMing.setAge(150);//不合法
        //输入xiaoMing.getAge().sout得到下面输出代码:
        System.out.println(xiaoMing.getAge());
    }
}
/*
小明
3
*/

public class Student {
    //属性私有

    private String name; //名字
    private int id; //学号
    private char sex; //性别
    private int age; //年龄

    //提供一些可以操作这些属性的方法
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }
    //Alt+Insert自动生成get、set方法


    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age>120||age<0)//安全性检查
            this.age = 3;
        else
            this.age = age;
    }
}

继承

  • 类与类之间的一类关系,还有依赖、组合、聚合等关系;
  • JAVA中只有单继承没有多继承;
  • 继承关系的两头分别为父类和子类,子类继承父类通过关键字extends来表示;
  • 子类可以继承父类非private的所有属性和方法;
  • 构造方法不能被继承;
  • 快捷键Ctrl+H查看继承树;
  • JAVA中所有类都直接或间接继承自Object类;
  • 子类通过super.属性/方法,可以调用父类属性或方法;
public class Application {
    public static void main(String[] args) {

        Student student = new Student();
        student.setName("朝小闇");
        student.say();//子类并未定义该方法,直接调用父类方法
        System.out.println("==========================");

        student.test("name");
        student.test2();
    }
}

public class Person {
    public String name = "刀刀木";

    public Person() {
        System.out.println("Person无参构造器执行了");
    }

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

    public void say(){
        System.out.println("Person说话了");
    }
}

public class Student extends Person {

    String name;
    public Student() {
        /*默认先调用父类无参构造器:super();
          如果显示调用super(),必须放在第一行中
          如果显示调用this(name),也必须放在第一行
          所以显示调用时只能调用父类或子类构造器,不能同时调用两者
        */
        System.out.println("Student无参构造器执行了");
        System.out.println("==========================");
    }

    public Student(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        return name;
    }

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

    public void test(String name){
        System.out.println(name);
        System.out.println(this.name);
        System.out.println(super.name);//private 权限父类属性无法调用
        System.out.println("==========================");
    }
    public void test2(){
        System.out.println(getName());
        System.out.println(this.getName());
        System.out.println(super.getName());
        System.out.println("==========================");
    }
    
}
/*
Person无参构造器执行了
Student无参构造器执行了
==========================
Person说话了
==========================
name
朝小闇
刀刀木
==========================
朝小闇
朝小闇
刀刀木
==========================

Process finished with exit code 0

*/
方法重写
  • 只有非静态方法可以重写;

  • 只可重写public权限方法;

  • 只存在子类和父类方法之间;

  • 方法名必须相同;

  • 参数列表必须相同;

  • 修饰符:范围可以扩大不能缩小 public > protected > default > private

  • 抛出的异常:可以被缩小但不能扩大,ClassNotFoundException < Exception

  • 方法体不同;

  • 普通调用:

public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.test();

        B b = new B();
        b.test();
    }
}

public class A {
    public void test(){
        System.out.println("A进行测试");
    }
}
public class B extends A {
    public void test(){
        System.out.println("B进行测试");
    }
}
/*
A进行测试
B进行测试
*/
  • 定义类型和创建类型不一致时(只有继承对象可以使用,上下都可转):
public class Application {
    public static void main(String[] args) {

        //静态方法调用
        //非重写,方法调用只和左边定义的数据类型相同
        C c = new D();
        c.test();

        D d = new D();
        d.test();

        //非静态方法重写调用
        //将父类引用指向了子类
        A a = new B();
        a.test();

        B b = new B();
        b.test();
    }
}

public class A {
    public void test(){
        System.out.println("A进行测试");
    }
}
public class B extends A {
    public void test(){
        System.out.println("B进行测试");
    }
}
public class C {
    public static void test(){
        System.out.println("C进行测试");
    }
}
public class D extends C {
    public static void test(){
        System.out.println("D进行测试");
    }
}
/*
C进行测试
D进行测试
B进行测试
B进行测试
*/

多态

  • 同一对象的方法可以根据发送对象的不同而采取多种不同的行为;

  • 一个对象的实际类型是确定的,但可以指向对象的引用类型有很多;

  • 多态存在的条件:

    • 有继承关系;
    • 子类重写父类方法;
    • 父类引用指向子类对象;
  • 多态是方法的多态,属性没有多态;

  • 类型转换异常:ClassCastException

  • static、final(存在常量池中)、private方法不能重写也就没有多态;

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

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定:父类的引用指向子类
        //右边是创建的实际类型,左边是定义的引用类型

        //能调用的方法都是自己的或继承父类的
        Student s1 = new Student();
        //可以指向子类,但是不能调用子类独有的方法
        Person s2 = new Student();
        Object s3 = new Student();

        s1.run();
        s2.run();//子类重写了父类方法,运行子类方法

        s1.eat();
        //s2.eat();//该句不能执行,对象能执行什么方法看左边引用类中是否含有,具体执行时还要看子类是否重写
        ((Student) s2).eat();//由高转低,可以执行
    }
}

public class Person {
    public void run(){
        System.out.println("run");
    }
}

public class Student extends Person {
    public void run(){
        System.out.println("son");
    }
    public void eat(){
        System.out.println("eat");
    }
}
/*
son
son
eat
eat
*/

instanceof

  • X instanceof Y,只要X、Y之间存在父子关系即相似
public class Application {
    public static void main(String[] args) {

        //Object > String
        //Object > Person > Student
        //Object > Person > Teacher

        Object object = new Student();

        System.out.println(object instanceof Student);
        System.out.println(object instanceof Person);
        System.out.println(object instanceof Object);
        System.out.println(object instanceof Teacher);
        System.out.println(object instanceof String);
        System.out.println("=============================");

        Person person = new Student();
        System.out.println(person instanceof Student);
        System.out.println(person instanceof Person);
        System.out.println(person instanceof Object);
        System.out.println(person instanceof Teacher);
//        System.out.println(person instanceof String);
//        编译时直接报错
        System.out.println("=============================");

        Student student = new Student();
        System.out.println(student instanceof Student);
        System.out.println(student instanceof Person);
        System.out.println(student instanceof Object);
//        System.out.println(student instanceof Teacher);
//        System.out.println(student instanceof String);
//        编译时直接报错
        System.out.println("=============================");
    }
}
/*
true
true
true
false
false
=============================
true
true
true
false
=============================
true
true
true
=============================

Process finished with exit code 0

*/

方法的强制转换

public class Application {
    public static void main(String[] args) {
        Person obj = new Student();
        //把父类转换成子类,向下转型,强制转换
        ((Student)obj).go();

        Student student = new Student();
        student.go();
        //把子类转换成父类,向上转型,直接转换,可能会丢失子类方法
        Person person = student;
    }
}

public class Person {
    {
        System.out.println("匿名代码块");
    }
    static{
        System.out.println("静态代码块");
    }

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

    public static void main(String[] args) {
        Person person = new Person();
    }
}
/*
静态代码块
匿名代码块
构造方法
*/
//先加载静态代码,再加载匿名代码,最后才是构造方法
//静态导入包之后调用Math.random可以直接使用random()调用
import static java.lang.Math.random;

public class Test {
    public static void main(String[] args) {
        System.out.println(random());
    }
}
//0.4934732130804633

抽象类和接口

抽象类

  • 抽象方法,继承自抽象类的子类(自身非抽象类时)必须要重写抽象类的抽象方法;
  • 只是一种约束,不能被new,只能被子类实现;
  • 抽象类可以写普通方法,但抽象方法必须在抽象类中;
  • 抽象类是单继承;
public abstract class Action {

    //抽象方法,继承抽象类的子类(非抽象类)必须要重写抽象类方法
    public abstract void doSomething();

}
public class A extends Action{
    @Override
    public void doSomething() {

    }
}

接口

  • 只有规范,无法写入具体方法;

  • 约束和实现分离;

  • 接口中所有定义方法都是默认public abstract;

  • 接口都需要有实现类;

  • 接口一般不定义常量,默认public static final;

  • 接口和抽象类一样,不能直接被实例化,必须被实现;

  • implements可以实现多个接口,但是必须重写所有方法;

public interface UserService {//接口

    void add();
    void delete();
}
public class UserServiceImpl implements UserService {//接口实现类
    @Override
    public void add() {

    }

    @Override
    public void delete() {

    }
}

内部类

  • 一个java文件中可以有多个class类(非内部类),但是只能拥有一个public类

成员内部类

  • 成员内部类不使用static静态修饰的前提下可以访问外部类的私有属性;
  • 在类中定义;
public class Application {
    public static void main(String[] args) {
        Outer outer = new Outer();

        Outer.Inner inner = outer.new Inner();
        inner.getId();
    }
}
//10
public class Outer {

    private int id = 10;
    public void out(){
        System.out.println("外部类方法");
    }

    public class Inner{//如果static化,则不能调用非static外部属性
        public void in(){
            System.out.println("内部类方法");
        }
        //可以调用外部类的私有属性
        public void getId(){
            System.out.println(id);
        }

        public Inner() {
        }
    }
}

匿名内部类

public class Test {
    public static void main(String[] args) {
        //没有名字初始化类,不用将实例保存到变量中
        new Apple().eat();
        //
        UserService userService = new UserService() {
            @Override
            public void hello() {

            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("eat");
    }
}

interface UserService{
    void hello();
}

静态内部类

  • public static class Inner{}

局部内部类

  • 在方法中定义class被称作局部内部类;
{//如果static化,则不能调用非static外部属性
        public void in(){
            System.out.println("内部类方法");
        }
        //可以调用外部类的私有属性
        public void getId(){
            System.out.println(id);
        }
        
        public Inner() {
        }
    }
}

匿名内部类

public class Test {
    public static void main(String[] args) {
        //没有名字初始化类,不用将实例保存到变量中
        new Apple().eat();
        //
        UserService userService = new UserService() {
            @Override
            public void hello() {

            }
        };
    }
}

class Apple{
    public void eat(){
        System.out.println("eat");
    }
}

interface UserService{
    void hello();
}

静态内部类

  • public static class Inner{}

局部内部类

  • 在方法中定义class被称作局部内部类;

狂神说java b站视频链接

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值