Java面向对象编程

2021.7.10

1.面向过程&面向对象

  • 面向过程的思想
    • 步骤清晰简单,第一步做什么,第二部做什么
    • 面向过程适合处理一些较为简单的问题
  • 面向对象思想
    • 物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行独立思考。最后,才对某个分类下的细节进行面向过程的思索。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题
  • 对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到围观操作,任然需要面向过程的思路去处理

2.面向对象

  • 面向对象编程(Object-Oriented Programming,OOP)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象来组织(封装)数据
  • 抽象:可以理解为将具体的东西用代码抽象来描述
  • 三大特效
    • 封装
    • 继承
    • 多态
  • 从认识角度考虑是先有对象后有类。对象,是具体的事物。类是抽象的,是的对象的抽象描述
  • 从代码运行角度考虑是现有类后有对象。类是对象的模板。

3.回顾方法的调用

静态方法和非静态方法,静态方法就是使用了Static修饰的

  • 静态方法,当一个类中的方法使用static来修饰,就是静态方法,在其他的类中被调用的时候,直接使用类名.方法名就可以直接调用。

  • 非静态方法:使用上述的调用方法调用非静态方法是非法的,需要先实例化一个对象,然后通过对象来调用次方法。例如:

    Student S = new Student();
    S.方法//直接调用
    

    总之,若要调用一个类的静态方法,需要先实例化一个对象,然后通过兑现过来调用此方法

4.类与对象的关系

  • 类是一种抽象出来的数据类型,它是对某一事物的整体描述/定义,但是不能代表某一个具体的事物
    • 动物类、植物类、手机类、电脑类;
  • 对象是抽象概念的具体实例
    • 某张三、某旺财等

5.构造器(构造方法)

  • 类中的构造器也成为构造方法,是进行创建对象的时候必须要调用的。

  • 构造器的特点

    • 必须和类的名字相同
    • 必须咩有返回值,也不能写void
    • 一个类及时什么都不写,它也会自然而然的构造一个构造器;
  • 构造器的作用

    • 构造方法一般用于初始化值;例如在构造方法中可以:

      public class Demo{
          String name;
          publlic Demo(){//构造方法
              This.name = "zhongguo"
          }
      }
      

      this就是指Demo的对象,当new一个对象的时候,其本质还是在调用构造方法,接下来调用的时候:

      public class Application {
          public static void main(String[] args) {
              Demo d = new Demo();
              System.out.println(d.name);//输出“zhongguo”;
          }
      }
      
    • 构造方法重载:当一个构造方法定义成为一个有参构造方法时,类构造器的无参构造方法就必须单独再显示定义,否则会报错;具体如下:

      public class Demo{
          String name;
          publlic Demo(){//无参的显式定义,若此方法不写,调用时非法
          }
          publlic Demo(String name){//有参构造器,形式参数name,并非第二行的name属性
              This.name = name;
          }
      }
      
    • 快捷键:alt+insert会生成构造器,弹出窗口选择:constructor,然后不选择成员直接回车就是无参的构造器;

  • 总结:

    • 构造器和类名相同,没有返回值
    • new的本质就是在调用构造器
    • 构造器可以初始化初始值
    • 如果使用无参构造,需要显式定义一个无参构造方法

6.封装

  • 一个类中该藏起来的需要藏起来,限制用户的访问权限

    • 程序设计追求“高内聚,低耦合”,
      • 高内聚:就是内部的而数据操作细节由自己完成,不允许外部干涉;
      • 低耦合:仅暴露少量的方法供外部使用
  • 封装

    • 信息的隐藏
  • 封装属于私有,深入理解get/set,get/set就是提供操作类里面一些属性的方法

  • 下面举例:

    public class Student {
        private String name;//对成员进行保护
        private int age;
        private String id;
        private char gender;
    
        public void setName(String name) {//给数据赋值
            this.name = name;
        }
    
        public String getName() {//取出赋值后的数据、下同
            return this.name;
        }
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    public class Application {
        public static void main(String[] args) {
            Student s1 = new Student();
    
            s1.setName("彭于晏");            //给数据赋值
            System.out.println(s1.getName());//取出值
    
            s1.setAge(30);
            System.out.println(s1.getAge());
        }
    }
    
  • 封装的意义:

    • 使得类里面的数据得到很好的保护,提高程序安全性

    • 隐藏类里面实现的细节

    • 增强了程序的可维护性,良好的封装便于改写程序的内部代码,例如在set方法中,可以加入一些约束条件,判断用户调用的时候时候是否合法安全:例如:

         public void setAge(int age) {
              if(age >120 || age <0){
                  System.out.println("年龄不合法");
              }else {
                  this.age = age;
              }
          }
      
    • 统一了接口(get/set)

  • 快捷键alt+insert,然后找到get或者set后可以快速生成get/set方法

7.继承

  • 继承的本质就是对某一批类的抽象,从而实现对世界更好的建模
  • extends的意思就是扩展。子类是父类的扩展
  • Java中类只有单继承,没有多继承
  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等
  • 继承关系的两个类,一个为子类,一个为父类,子类继承父类,使用关键字extends
  • 子类和父类之间,从意义上讲应具有“is a”的关系
  • 子类可以继承父类的所有public方法和公有属性,当父类的属性使用private或者protacted
  • 快捷键ctrl+h,调出继承树,发现父类会继承一个叫做Object的类,在Java中,所有的类,都会默认或者直接继承一个叫做Object的类

8.super详解

  • super和this关键字的区别

    • this指的就是当前所在的类,可以想象成当前类的一个实例化对象

    • super是指当前类的父类,可以当做父类的实例化对象

    • 当父类的方法是私有时,super不能调用父类的私有方法

    • 当在第三方类中实例化子类时,会默认首先调用父类的构造方法,然后调用子类的构造方法:

      public class Person {
          public Person() {
              System.out.println("父类构造器");
          }
      }
      
      public class Student01 extends Person{
          public Student01() {
              System.out.println("子类构造器");
          }
      }
      
      public class Application {
          public static void main(String[] args) {
              Student01 s = new Student01();
          }
      }
      

      结果:

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

    • 并且,调用父类的无参构造方法(auper.xxx)必须放在第一行(如果要显式调用super的话),this.xxx也一样,如果super.XXX和this.XXX在同一个地方显式调用的话可能会报错,即不能同时调用;

9.方法的重写

  • 重写都是方法的重写,和属性无关

  • 当父类和子类的方法属于静态方法时,父类的引用可以指向子类,下面代码中, B extends A,test()方法都使用static修饰:

    public class A {
        public static void test(){
            System.out.println("A");
        }
    }
    
    public class B extends A{
        public static void test(){
            System.out.println("B");
        }
    }
    
    public class Application {
        public static void main(String[] args) {
            B b = new B();
            b.test();
            A a = new B();//父类的引用a指向子类B
            a.test();//调用的依旧是A中的test()
        }
    }
    

    结果:

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

  • 重写

    • 当父类和子类的方法是非静态方法时,方法名字一样时就是重写了,且修饰符应该是public

      public class A {
          public  void test(){
              System.out.println("A");
          }
      }
      
      public class B extends A{
          @Override
          public void test() {//子类重写了父类的test()
              System.out.println("B");
          }
      }
      
      public class Application {
          public static void main(String[] args) {
              B b = new B();
              b.test();
              A a = new B();//父类的引用a指向子类B
              a.test();//因为子类B重写了A的test方法,输出B,因此重写后调用的是B里面的重写方法
          }
      }
      

      结果:

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

    • 重写只针对于子类和父类的

  • 需要有继承关系才能重写,而且是子类重写父类的方法

  • 方法名必须相同并且是public方法

  • 修饰符的范围只能扩大:即子类重写的方法的范围(即修饰符)要大于父类的范围,(public > protected > default > private)

  • 抛出的异常是相反的,即抛出的异常的范围必须是缩小的,不能扩大:

    重写异常抛出范围不能大于父类

  • 记住快捷键:alt+insert 然后选中Override

  • 为什么需要重写?

    • 子类不一定需要或者不一定满足

9.多态

  • 增强程序的可扩展性

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

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

  • 多态的存在条件:

    • 有继承关系

      public class A {
            public void test(){
                System.out.println("A");
          }
      }
      
      public class B extends A{
          
      }
      
    • 子类重写父类方法

      public class B extends A{
          @Override
          public void test() {
              System.out.println("B");
          }
      }
      
    • 父类的引用指向子类对象

      public class Application {
          public static void main(String[] args) {
              A a = new B();//父类的引用a指向了子类B
              a.test();
          }
      }
      

    *注意:*多态是方法的多态,属性没有多态性,

    ​ static方法属于类,不能重写

    ​ final是属于常量

    ​ private方法属于私有

10.instanceof和类型转换

  • instanceof:判断一个对象是什么类型,判断两个类是否有父子关系

    X instenceof Y
    

    意义就是判断X指向的类型或者X对象跟Y是不是有父子关系;有就会返回true,没有就会返回false,包括“子孙关系”;

  • 对象类型的强制转换

    当一个父类的引用(对象)指向了一个子类(Person person = new Student(),Person是Student的父类),同时需要用父类的引用来调用子类中的没有被重写的方法时,是不能直接调用的,需要强制转换为子类的引用才能对子类中的方法进行调用。强制转换的语法:((子类)父类对象),调用子类的方法时,就可以使用((子类)父类对象).XX()来实现,父转子,也就是乡下强制转

    例如:

    public class Person {
        
    }
    
    public class Student01 extends Person{
        public void go(){
            System.out.println("子类的方法");
        }
    }
    
    public class Application {
        public static void main(String[] args) {
            Person person  = new Student01();//指向子类的引用person
            ((Student01)person).go();//将父类引用person强制转换为Student类的引用
        }
    }
    
    

11.static小结

  • 修饰成员属性或者成员方法时,称之为静态属性或者静态方法

  • 调用静态成员或者静态方法时,可以使用类来直接调用,比如;

    public class Application {
        private static int age;
        private int score;
        public  static void say(){
            System.out.println("静态方法");
        }
        public   void go(){
            System.out.println("非静态方法");
        }
        public static void main(String[] args) {
            Application a = new Application();
            System.out.println(Application.age);//静态属性age可以直接通过类就可以访问
            Application.say();//静态方法say()可以直接通过类就可以访问
            
            System.out.println(a.score);//非静态属性需要用对象a进行访问
            a.go();//非静态方法需要用对象a进行访问
        }
    }
    
  • 静态代码快、静态构造方法、匿名构造方法的加载顺序问题

    public class Demo {
        public static void main(String[] args) {
            Demo demo1 = new Demo();
            //System.out.println("===============");
            //Demo demo2 = new Demo();
        }
        {
            System.out.println("匿名代码快");
        }
        static {
            System.out.println("匿名代码块");
        }
    
        public Demo() {
            System.out.println("构造方法");
        }
    }
    
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9bqPPcs-1626246744874)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210713003227689.png)]
    image
    当再次实例化一个对象执行时候;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FLgnrDaw-1626246744877)(C:\Users\77568\AppData\Roaming\Typora\typora-user-images\image-20210713003816259.png)]
    image
    结论:静态代码块是最先加载的,反而构造器的加载排在最后,再次初始化一个类的时候,静态方法不再加载了,说明,静态方法只会执行一次;

12.抽象类

  • abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。

  • 抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类

  • 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。

  • 抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的。

    public abstract void test();
    
  • 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。也就是说子类一定要重写抽象父类中的抽象方法;除非子类也是一个抽象类

    public abstract class Demo02 {//抽象类
        public abstract void test();//抽象方法
    }
    
    public class Demo03 extends Demo02 {
        @Override
        public void test() {//重写父类的抽象方法,否则报错
        }
    }
    
  • 抽象类只能是单继承

13.接口

  • 普通类:只有具体实现

  • 抽象类:具体实现和规范(抽象方法)都有!

  • 接口:只有规范!

  • 接口就是规范,定义的是一组规则,体现了现实世界中“如果你是.….则必须能…”的思想。如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人。

  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。

  • OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如c++、java、c等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。

  • 声明类的关键字是class,声明接口的关键字是interface

  • 接口中的方法默认是抽象的;

  • 接口都需要实现类,其实现类通过使用implements来初始化,命名规则一般是接口名字+Ipml,并且实现类需要重写接口里面的所有方法

  • 可多继承

    public interface Demo04 {
        //接口中的所有定义其实都是抽象的
        public abstract void say(String name);
        void look();
        public void run();
        public void jump();
    }
    
    public interface Demo05 {
        void hello();
    }
    
    //实现类需要重写借口里面的方法,否则报错
    public class DemoIpml implements Demo04,Demo05{//实现了多继承
        @Override//实现类需要重写借口里面的方法
        public void say(String name) {
    
        }
    //实现类需要重写借口里面的方法
        @Override
        public void look() {
    
        }
    //实现类需要重写借口里面的方法
        @Override
        public void run() {
    
        }
    //实现类需要重写借口里面的方法
        @Override
        public void jump() {
    
        }
    //实现类需要重写借口里面的方法
        @Override
        public void hello() {
    
        }
    }
    
  • 接口的属性

    • 在借口中定义的属性默认为常量,例如:

      public interface Demo05 {
          public static final int age = 90;//其中,public static final都是默认的 
      }
      

14.内部类

  • 内部类就是在一个类的内部在定义一个类,比如,A类中定义一个B类,那么B类相对A类来说就称为内部类,而A类相对B类来说就是外部类了。

  • 成员内部类

    • 内部类可以访问外部内的属性和方法

    • 如何实例化外部类和内部类?

      public class Out {//外部类
          private int age = 10;
          public void sayOut(){
              System.out.println("外部方法");
          }
          public class In{//内部类
              public void sayIn(){
                  System.out.println("这是内部类");
              }
              public int getAge(){//内部类访问外部类的私有变量
                  return age;
              }
          }
      }
      
      public class Application01 {
          public static void main(String[] args) {
              Out out = new Out();//实例化一个外部类
              Out.In in = out.new In();//初始化内部类;
              System.out.println(in.getAge());
          }
      }
      
  • 静态内部类:使用static修饰的内部类

    public class Out {//外部类
        private int age = 10;
        public void sayOut(){
            System.out.println("外部方法");
        }
        public static class In{//静态内部类
            public void sayIn(){
                System.out.println("这是内部类");
            }
        }
    }
    

    使用静态内部类之后,就无法访问外部类的非静态属性了,因为static总是在最前面实例化,外部非静态属性还没有初始化;

  • 局部内部类

    public class Out01 {
        private int age = 10;
        
        public void sayOut(){
             class In{//局部内部类
                public void sayIn(){
                    System.out.println("这是局部内部类");
                }
            }
        }
    }
    
  • 匿名内部类

    一个Java类中可以多个class类,但是只能有一个public class类,不用讲实例保存到变量中;

    public class Out {//外部类
        private int age = 10;
        public void sayOut(){
            new A().eat()//匿名内部类,不用讲实例保存到变量中
        }
    }
    class A{
        public void eat(){
             System.out.println("HelloWorld"); 
        }
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值