DAY04面向对象OOP

DAY04 面向对象OOP

1.什么是面向对象

面向对象:属性加方法

本质:以类的方式组织代码,以对象的方式封装数据

特征:

  • 封装:将数据封装,对外提供使用数据的接口

  • 继承:子类会有父类的属性和方法

  • 多态

先有类,后有对象


2.回顾方法的

2.1方法定义

定义:修饰符 返回值类型 方法名(参数表){……}

return:结束方法,返回结果

方法名:小写开头,驼峰原则,见名知意

参数列表:参数类型 参数名,……

异常抛出:io流中会出现异常

public void readFile(String path) throws IOException{……}

2.2方法调用

  • 静态方法:加了static

    静态方法在其它类中,既可以通过类名.方法名()调用,也可以实例化类创建对象来调用方法;在本类方法中,可以直接调用。而其他方法必须实例化,才可调用。

    //以下代码均在一个类中

    //情况1:都为普通方法,可以直接调用对方

    public void a(){b();}
    public void b(){a();}

    //情况2:都为静态方法,可以直接调用对方

    public static void a(){b();}
    public static void b(){a();}

    //情况3:其中一个为静态方法,另一个方法不可直接调用对方

    public static void a(){b();}
    public void b(){a();} //错误

    //原因:静态方法是和类一起加载的,而非静态方法在实例化后才存在

    静态方法是和类一起加载的,而非静态方法在实例化后才存在

  • 形参和实参:调用时的括号中是实参,定义的括号中是形参

  • 值传递:java中的调用为值传递

  • 引用传递

    //引用传递:对象做参数,本质仍为值传递

    public class A{
       public static void main(String[] args){
           Person person = new Person();
           sout(person.name);
           change(person); //引用传递,将地址的值传过去
           sout(person.name);
      }
       
       public static void change(Person person){
           person.name = "XXX"; //通过地址去找到了相应的属性并作修改
           //如果改为 person = xxx;,则原本的person也不会改变
      }
    }

    Class Person{
    String name;
    }

3.类与对象的创建

类是一种抽象的数据类型,它是对某一类事务整体描述,但不能代表某一个个具体事务

public class A{
   String name;
   
   public void xxx();
}

对象是抽象概念类的一个具体实例

//类实例化后返回一个自己的对象
A a = new A();
a.name = "xxx";

4.构造器

  • 和类名相同

  • 没有返回值

  • new本质是调用构造方法,初始化值

  • 定义有参构造器,必须显示定义无参构造器


public class A{
   String name;
   
   public void xxx();
   
   //没有构造方法时,相当于默认有一个如下构造方法
   //public A(){}
   
   //显示定义一个构造器
   //实例化初始值
   public A(){
       this.name = "XXX";
  }
   
   //有参构造器
   //一旦定义有参构造,就必须显示定义无参构造,否则会报错
   public A(String name){
       this.name = name;
  }
}

idea快捷键:alt+insert快捷构建构造函数

5.创建对象内存分析


public class pet{
   String name;
   int age;
   //默认的无参构造
   
   public void bark();
}

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

在内存中的状态:

  1. 进入类Application时

     

     

  2. new Pet()时

     

     

  3. 给属性赋值时

     

     

  4. 内存中分为堆栈,堆中又有方法区

     

     

  • 引用类型

    除了基本类型都是引用类型,对象(堆)是通过引用(栈)来操作的

 

6.封装详解

概念:将数据封装在内部,禁止直接访问一个对象中的数据的实际表示,而应通过操作接口来实现,实现信息隐藏。

 

如何实现:属性设置为私有,private,get/set方法。

 

意义:

  1. 提高程序安全性,保护数据

  2. 隐藏代码实现

  3. 统一接口

  4. 增强了可维护性


public class pet{
   private String name;
   private int age;
   
   //提供获得数据和操作数据的方法
   public String getName(){return this.name;}
   public void setName(String s){this.name = s;}
}

public class Application{
 
   public static void main(String[] args){
       Pet dog = new Pet();
       //此时不再合法
       //dog.age = 3;
//dog.name = "旺财";

       dog.setName("旺财");
       System.ou.println(dog.getName());
  }
}

 

7.继承

7.1继承的一些概念与例子

 

  • 关键字:extends,子类是父类的扩展与派生

  • Java中没有多继承:一个子类只有一个父类,一个父类可以有多个子类


//Java中所有的类都默认直接或者间接继承Object类
public class Person{
   
   public int money = 10_0000;
   
   public Person{
       System.ou.println(“产生一个人”);
  }
   
   protected String name = "xxx";
   
   public void say(){
       System.ou.println(“我是人”);
  }
}

//间接继承Objiect类
public class Student extends Person{
   
   protected String name = "yyy";
   
   public Student(){
       //隐藏:会先调用父类的无参构造
       //等价于:super(); 但是该代码必须放在构造器第一行
       super(); //可省略
       //若父类中仅有有参的构造器,则子类的无参构造会报错,除非显示的在子类的无参构造器中调用父类的有参构造,如:super(参数表);
       System.ou.println(“产生一个学生”);
  }
   
   public void say(){
       System.ou.println(“我是学生”);
  }
   
   //子类会继承父类的public的属性和全部方法
   
   //IDEA快捷键:Ctrl+H,继承树
   
   //super的用法:可以访问protected和public
   public void superTest(){
       System.ou.println(this.name);//输出自己的对应属性
       System.ou.println(super.name);//会输出父类的对应属性
  }
   
   //super的用法
   public void superTest2(){
       say(); //调用自己的
       this.say(); //调用自己的
       super.say(); //调用父类的
  }
}

public class Application{
 
   public static void main(String[] args){
       Student student = new Student();
       //会先输出产生一个人,再输出产生一个学生
       //说明调用子类构造器之前先隐含的调用了父类的无参构造
  }
}

  • super注意点

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

    • super只能出现在子类的方法和构造方法中

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

  • VS this

    • 本身调用者这个对象

    • super代表父类对象的引用

    • this没有继承也可以用

    • super只能在继承条件下使用

    • this();本类的构造

    • super();父类的构造

 

7.2方法重写

重写与属性无关

重写与静态方法无关

重写的原因:父类的方法子类不一定需要,或者不能满足子类的要求


public class B{
   public void print(){
       System.ou.println("Person");
  }
}

public class A extends B{
   //重写
   @override //注解,有功能的注释
   public void print(){
       System.ou.println("Student");
  }
}

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

  • 重写的总结

    • 前提:有继承关系,子类重写父类的方法,不能重写属性

    • 方法名必须相同,参数列表必须相同(与重载不同),方法体不同

    • 抛出的异常:必须小于父类抛出的异常,不可扩大

      Exception>ClassNotFoundException

    • 修饰符:子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符:public>protected>default>private

      特殊情况:子类不能重写父类中声明为private权限的方法

 

7.3多态

概念:同一个方法,根据发送对象的不同,而采用不同的操作


public class Person{
   
   public void say(){
       System.ou.println(“我是人”);
  }
   
   public void eat(){
       System.ou.println(“人吃”);
  }
}

public class Student extends Person{
   
   
   public void say(){
       System.ou.println(“我是学生”);
  }
   
   //子类有父类没有的方法
   public void run(){
       System.ou.println(“学生run”);
  }
}

public class Application{
 
   public static void main(String[] args){
       //对象的实际类型时确定的
       //new Student();
       //new Person();
       
       //指向对象的引用的类型不确定:父类的引用可以指向子类
       //Student定义的子类,能调用自己的方法和继承自父类的方法
       Student s1 = new Student();
       //使用Person定义的,可以指向子类,不能调用子类独有的方法
       Person s2 = new Student();
       Object s3 = new Student();
       
       //对象能调用哪些方法,主要是看定义时左侧的类型
       s2.run();//会报错,因为s2的引用类型是父类,不能调用仅仅子类有的类
       s2.say();//会输出我是学生,因为子类重写了父类的方法,而s2指向的是子类对象
       s2.eat();//输出“人吃”,子类没有重写父类的方法,调用父类的方法
  }
}

  • 多态的注意事项

    1. 方法的多态,属性没有多态

    2. 父类和子类一定条件下可以类型转换(怎么转换的?)

    3. 条件:继承关系,方法需要重写,父类引用指向子类对象

    4. 哪些无法被重写:

      • static方法:属于类

      • final:常量

      • private

 

8.instanceof与类型转换

  • instanceof:判定两个类型是否有关联?


Object s = new Student();

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


System.ou.println(s instanceof Student);//true
System.ou.println(s instanceof Person);//true
System.ou.println(s instanceof Object);//true
System.ou.println(s instanceof Teacher);//false
System.ou.println(s instanceof String);//false

Person s1 = new Student();

System.ou.println(s1 instanceof Student);//true
System.ou.println(s1 instanceof Person);//true
System.ou.println(s1 instanceof Object);//true
System.ou.println(s1 instanceof Teacher);//false
System.ou.println(s1 instanceof String);//编译报错

Student s2 = new Student();

System.ou.println(s2 instanceof Student);//true
System.ou.println(s2 instanceof Person);//true
System.ou.println(s2 instanceof Object);//true
System.ou.println(s2 instanceof Teacher);//编译报错
System.ou.println(s2 instanceof String);//编译报错

//猜想
Object p = new Person();
System.ou.println(p instanceof Student);//false
System.ou.println(p instanceof Person);//true
System.ou.println(p instanceof Object);//true
System.ou.println(p instanceof Teacher);//false
System.ou.println(p instanceof String);//false
//在IDEA中验证猜想正确

  • 总结:对于x instanceof y

    • 若x与y存在父子关系的一点关联则可以编译通过,否则会报错

    • x指向的类型若为y的子类型,或者为y类型则返回true,否则返回false


  • 引用类型的类型转换

    • 父类(高)转子类(低):强制转换

      如:

      Person s = new Student();
      Student s1 = (Student)s;//强制
    • 子类转父类,自动转换,会丢失子类独有父类没有的方法与子类重写的方法

      Student s = new Student();
      Person p = s;//自动

      public class Application {
         public static void main(String[] args) {
             //父转子
             Person s = new Student();
             //s.eat();   编译错误
            ((Student) s).eat();    // 强转为子类型

             s.say();       //输出学生在说话,多态,指向的对象为学生,所以调用学生的

             //子转父,不需强制转换
             Student s2 = new Student();

             Person p = s2;  //直接会自动转换
             //p.eat(); 编译错误,丢失了子类独有的方法
        }
      }

      public class Student extends Person{
         //父类被子类重写的方法
         public void say() {
             System.out.println("学生在说话");
        }

         //子类独有的方法
         public void eat() {
             System.out.println("学生在吃");
        }
      }

      public class Person {
         //父类未被子类重写的方法
         public void run() {
             System.out.println("人在跑");
        }

         //父类被子类重写的方法
         public void say() {
             System.out.println("人在说话");
        }

      }

 

9.static详解

  • 静态属性

    可以直接使用类名来访问

  • static方法

    跟类同时加载,可以直接使用类名来调用

    • 静态方法不能调用直接调用其他方法,因为静态方法加载时,其它方法还不存在;静态方法可以调用静态方法。

    • 其他方法可以直接调用static方法


      public void run(){
         go();//合法
      }

      public static void go(){
         run();//不合法
      }

  • 静态代码块

    //静态导入
    import static java.lang.Math.random
    import static java.lang.Math.PI

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

    //静态代码块,类加载时运行且只运行一次
    static{
      System.out.println("静态代码块");
    }
       
       //new一个对象时执行
       public Person(){
           System.out.println("构造方法");
      }
       
       public static void main(String[] args) {
           Person p = new Person();
           //输出结果:
      /*
      静态代码块
      匿名代码块
      构造方法
      */
           
           Person p1 = new Person();
           //输出结果:静态代码块不再执行,说明静态代码块只在类加载时执行一次
      /*
      匿名代码块
      构造方法
      */
           
           System.out.println(random()); //静态导入的,可直接使用
           System.out.println(random()+PI);
      }
    }

     

10.抽象类

关键字:abstract


//抽象类:类 单继承 extends(接口可以多继承)
public abstract class Person {
   
   //抽象方法,只有方法名,没有方法体,需要别人来实现
   //有抽象方法,则必须将类也修饰为抽象
   public abstract void printJob;
   
   //抽象类可以有不抽象的方法
   public void sayHello(){
       System.out.println("Hello");
  }
   /*
   1.抽象类不能用new实例化,只能靠子类来实现
   2.抽象类可以写普通方法
   3.抽象方法必须在抽象类中
   */
}

public class Student extends Person {
   
   //抽象类的方法,它的子类必须要实现它的方法,除非它的子类也是抽象类
   public abstract void printJob{
       System.out.println("学生");
  }
}

public class Teacher extends Person {
   
   //抽象类的方法,它的子类必须要实现它的方法,除非它的子类也是抽象类
   public abstract void printJob; //不实现会报错
}

10.1 思考题

  • 抽象类无法通过new实例化对象,那么抽象类存在构造器吗?

     

  • 抽象类存在的意义是什么?

    将共有的东西抽象出来,提高开发效率

 

11.接口

接口只有规范,自己无法写方法,比抽象类更抽象。约束和实现分离:面向接口编程

 

本质:接口的本质时契约,即规范,制定好以后实现它的类都要遵守。


//接口
public interface UserService{
   //接口中定义常量,默认修饰为public static final,但一般不使用
   int i = 99;
   
   //只能写方法,不能写方法的实现,并且不写修饰符时默认为public abstract
   void add(String name);
   void delete(String name);
   void update(String name);
   void search(String name);
}

public interface TimeService{
   //只能写方法,不能写方法的实现,并且不写修饰符时默认为public abstract
   void set(String time);
}

//类可以通过implements实现接口
//实现接口的类,必须重写(实现)接口中的方法
//使用接口可以侧面实现多继承,但实现的所有接口中的方法都需要重写
public class StudentService implements UserService,TimeService{
   public void add(String name){
       
  }
   public void delete(String name){
       
  }
   public void update(String name){
       
  }
   public void search(String name){
       
  }
}

  • 接口的作用

    1. 约束

    2. 定义一些方法,让不同的类来实现

    3. 方法默认为:public abstract

    4. 属性默认修饰:public static final

    5. 接口不能被实例化,接口中没有构造方法

    6. implements可以实现多个接口

    7. 实现接口时,必须重写接口中的所有方法

 

内部类

在一个类中有定义一个类,这个内部定义的类就是内部类

做到能够看懂,不一定非要去使用这些写类的方式


  1. 成员内部类

    public class Out{
       private int id = 10;
       public void out(){
           System.out.println("out method");
      }
       
       public class Inner{
           public void in(){
               System.out.println("in method");
          }
           
           //可以获得外部类私有属性,这是其他类做不到的
           public void getID(){
               System.out.println(id);
          }
      }
    }

    public class Application {
       public static void main(String[] args) {
           Out out = new Out();
           
           //必须通过外部类的实例化对象才能实例化内部类,以下是实现方式
           Out.Inner inner = out.new Inner();
           //也是通过实例化对象来实例化内部类
           Out.Inner inner1 = new Out().new Inner();
           
           //Out.Inner inner1 = Out().new Inner();错误
      }
    }

  1. 静态内部类

    public class Out{
       private int id = 10;
       private static int num = 20;
       public void out(){
           System.out.println("out method");
      }
       
       //加上static即为静态内部类
       public static class Inner{
           public void in(){
               System.out.println("in method");
          }
           
           //可以获得外部类私有属性,这是其他类做不到的
           public void getID(){
               //System.out.println(id);此时无法获取id属性,因为静态内部类加载时id还不存在
               System.out.println(num); //对于同为静态的属性num,可以获取
          }
      }
    }

     


  1. 同一个java文件中的类

    public class Out{
       private int id = 10;
       private static int num = 20;
       public void out(){
           System.out.println("out method");
      }
    }

    //一个java文件可以有多个类,但只能有一个为public
    class AOut{
       
    }

     


  1. 方法中的类,局部内部类

    public class Out{
       private int id = 10;
       private static int num = 20;
       public void out(){
           //局部内部类
           class Inner{
               public void in(){
                   
              }
          }
           System.out.println("out method");
      }
    }

     


  1. 匿名内部类

    public class Out{
       
        public static void main(String[] args) {
            //没有名字类实例化类,不用将引用变量指向实例
            new AOut().method();
           
            //匿名内部类
            A a = new A(){
               
                public void hello(){
                    System.out.println("hello");
                }
            }
        }
    }

    //一个java文件可以有多个类,但只能有一个为public
    class AOut{
       public void method(){
           System.out.println("AOut method");
      }
    }

    interface A{
       void hello();
    }
posted @ 2021-11-09 15:22  陆不平  阅读(113)  评论(0)    收藏  举报