Java基础(7)— 面向对象

面向对象

初识面向对象

面向过程&面向对象

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

什么是面向对象?

  • 面向对象编程(Object-Oriented Programming, 00P)
  • 面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
  • 抽象:编程思想
  • 三大特性
    • 封装
    • 继承
    • 多态
  • 从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象
  • 从代码运行角度考虑是先有类后有对象。类是对象的模板

方法回顾和加深

方法的定义

  • 修饰符

  • 返回类型

    /*
        修饰符 返回值类型 方法名(...){
        	方法体
        	return 返回值
        }
    */
    public String sayHello(){
    	return "hello,world!";
    }
    
    public int max(int a, int b){
    	return a > b ? a : b; //三元运算符
    }
    
  • break 和 return 的区别

    • break:跳出switch,结束循环
    • return:结束方法,返回结果
  • 方法名:注意命名规范就OK,见明知意

  • 参数列表:(参数类型 参数名)...

  • 异常抛出:疑问后面讲解

    public void readFile(String file) throws IOException{ }
    

方法的调用

  • 静态方法

  • 非静态方法

    //学生类
    public class Student {
        //静态方法
        public static void say(){
            System.out.println("学生在说话....");
        }
        //非静态方法
        public void eat(){
            System.out.println("学生在吃饭....");
        }
    }
    public static void main(String[] args) {
        //静态方法调用
        Student.say();
        /*
            非静态方法调用
            实例化这个类  new
            对象类型 对象名 = 对象值;
         */
        Student stu = new Student();
        stu.eat();
    }
    

  • 形参和实参

    public static void main(String[] args) {
        //形参和实参类型要对映
        //int add = new Demo03().add(2,3);
        int add = add(2,3);
        System.out.println(add);
    }
    public static int add(int a,int b){
        return a+b;
    }
    
  • 值传递和引用传递

    扫描二维码关注公众号,回复: 11474227 查看本文章
    //值传递
    public static void change(int a){
        a = 10;
    }
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a); //1
        change(1);
        System.out.println(a);
    }
    
    //引用传递:对象,本质还是值传递
    //对象,内存!
    //定义一个Person类,有个属性是name
    class Person{
        String name;
    }
    public static void change(Person person){
        //person是一个对象,指向的Person person = new Person();这是具体的人,可以改变属性。
        person.name = "叶凡";
    }
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);//null
        change(person);
        System.out.println(person.name);//???
    }
    
  • this 关键字(继承和多态的时候学)

对象的创建分析

类与对象的关系

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

    • 动物、植物、手机、电脑....
    • Person类、Pet类、 Car类等,这些类都是用来描述/定义某类具体的事物应该具备的特点和行为
  • 对象是抽象概念的具体实例

    • 张三就是人的一个具体实例,张三家里的旺财就是狗的一个具体实例
    • 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念
  • 构造器必须要掌握

创建与初始化

  • 使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用

    //学生类
    public class Student {
        //属性/字段
        String name;
        int age;
        //方法
        public void study(){
            System.out.println(this.name + "在学习");
        }
    }
    //一个项目应该只存在一个main方法
    public class Application {
        public static void main(String[] args) {
            /*
            类:抽象的,实例化
            类实例化后会返回一个自己的对象
            jack/tom 对象就是Student类的具体实例
             */
            Student jack = new Student();
            Student tom = new Student();
    
            jack.name = "jack";
            jack.age = 3;
            System.out.println(jack.name);
            System.out.println(jack.age);
    
            tom.name = "tom";
            tom.age = 3;
            System.out.println(tom.name);
            System.out.println(tom.age);
        }
    }
    

构造器详解

  • 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的,并且构造器有以下俩个特点

    • 必须和类的名字相同
    • 必须没有返回类型,也不能写void
  • IDEA生成构造器快捷键:Alt+Insert

    public class Person {
        /*
        一个类即使什么都不写,也会存在一个方法(空参构造)
            public Person() {}
         */
        String name;
        //实例化初始值
        /*
        1.使用new关键字,本质是再调用构造器
         */
        public Person(){
        }
        /*
        2.有参构造,一旦定义了有参构造,无参必须显示定义
         */
        public Person(String name){
            this.name = name;
        }
    }
    public static void main(String[] args) {
        //实例化一个对象
        Person person = new Person("叶凡");
        System.out.println(person.name);
    
    }
    

创建对象内存分析

  • 代码

    public class Pet {
        public String name;
        public int age;
        public void shout(){
            System.out.println("叫了一声!");
        }
    }
    public class Application {
        public static void main(String[] args) {
            Pet dog = new Pet();
            dog.name = "旺财";
            dog.age = 3;
            dog.shout();
            Pet cat = new Pet();
            cat.name = "汤姆";
            cat.age = 2;
            cat.shout();
        }
    }
    
  • 示意图

  • 小结:

    • 类与对象

      • 类是一个模板,抽象
      • 对象是一个具体的实例
    • 方法

      • 定义,调用!
    • 对象的引用

      • 引用类型:基本类型(8)之外的,对象是通过引用来操作的:栈 ---> 堆
    • 属性:字段Field/成员变量

      • 默认初始化(char-u0000/boolean-false/引用-null)
      • 修饰符 : 属性类型 属性名 = 属性值、
    • 对象的创建和使用

      • 必须使用new关键字创造对象,构造器 Person Jack = new Person();
      • 对象的属性 jack.name/jack.age
      • 对象的方法 jack.sleep();
      • 静态的属性
      • 动态的行为

面向对象三大特性

封装

  • 该露的露,该藏得藏

    • 我们程序设计要追求 "高内聚,低耦合"。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
  • 封装(数据的隐藏)

    • 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
    • 记住一句话:属性私有,set/get (快捷键 Alt+Insert)
    public class Student {
        /*
        private 属性私有
         */
        private String name;//名字
        private int id;     //学号
        private char sex;   //性别
        private int age;    //年龄
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            //可以加一些校验
            if(age > 120 || age < 0){
                age = 3;
            }
            this.age = age;
        }
        /*
        提供一些可以操作这个属性得方法
        提供一个public的get/set方法
         */
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    public static void main(String[] args) {
        Student stu = new Student();
        stu.setName("叶凡");
        System.out.println(stu.getName());
        stu.setAge(999);
        System.out.println(stu.getAge());
    
    }
    
  • 好处

    • 提高程序的安全性,保护数据
    • 隐藏代码的实现细节
    • 统一接口,形成规范
    • .系统可维护性增加了

继承

  • 继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模

  • extends的意思是“扩展”,子类是父类的扩展

  • JAVA中类只有单继承,没有多继承

  • final修饰的类不能被继承

  • 继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等

    • 继承关系的两个类,一个为子类(派生类),一个为父类(基类),子类继承父类,使用关键字extends来表示
    • 子类和父类之间,从意义上讲应该具有"is a"的关系
    /*
    Person 人  父类/基类
    java中,所有类都直接或间接继承Object类
    */
    public class Person {
        /*
        四个级别:
            public
            protected
            default
            private
         */
        private int money = 10_0000_0000;
        public void say(){
            System.out.println("说了一句话....");
        }
        public int getMoney() {
            return money;
        }
        public void setMoney(int money) {
            this.money = money;
        }
    }
    public static void main(String[] args) {
        Student stu = new Student();
        stu.say();
        System.out.println(stu.getMoney());
    }
    
  • super注意点

    • super调用父类的构造方法,必须在构造方法的第一行
    • super 必须只能出现在子类的方法或者构造方法中
    • super 和 this 不能同时调用构造方法(因为都要在第一行)
  • VS this

    • 代表对象不同

      this:代表调用者这个对象

      suoer:代表父类对象的应用

    • 前提

      this:没有继承也可以用

      super:只能在继承条件才可以使用

    • 构造方法

      this:本类的构造

      super:父类的构造

  • Ctrl + H:显示继承关系

    //父
    public class Person {
       protected String name = "叶凡";
       public void print(){
           System.out.println("Person");
       }
       public Person(){
           System.out.println("Person无参构造执行了");
       }
    }
    //子
    public class Student extends Person {
        private String name = "叶依水";
        public void print(){
            System.out.println("Student");
        }
        public Student(){
            //隐藏代码super():调用了父类的无参构造
            System.out.println("Student无参构造执行了");
        }
        public void test1(String name){
            System.out.println(name); //石昊
            System.out.println(this.name); //叶依水
            System.out.println(super.name);//叶凡
        }
        public void test2(){
            print();
            this.print();
            super.print();
        }
    }
    //效果
    public static void main(String[] args) {
        Student stu = new Student();
        stu.test1("石昊");
        stu.test2();
    }
    
  • 方法重写

    • 前提:需要有继承关系,子类重写父类的方法!

      • 方法名必须相同
      • 参数列表必须相同
      • 修饰符:范围可以扩大,但不能缩小 (public > protected > default > private)
      • 抛出异常:范围,可以被缩小,不能扩大 ClassNotFoundException --> Exception
    • 子类的方法和父类的方法必须要一致,只方法体不同

    • 为什么需要重写?

      • 父类的功能子类不需要或者不满足!
      • Alt + Insert ---> override
      //重写都是方法的重写,与属性无关
      public class A{
          public void test(){
              System.out.println("A-->test()");
          }
      }
      public class B extends A{
          @Override //重写,注解:有功能的注释
          public void test() {
              super.test();
          }
      }
      //运行
      public class Application {
          /*
          静态方法和非静态方法区别很大:
              静:方法调用只和左边类型有关
              非静:才可以重写,子类重写了父类的方法
           */
          public static void main(String[] args) {
              B b = new B();
              b.test();
              //父类指向子类
              A a = new B();
              a.test();
          }
      }
      

多态

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

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

  • 多态存在的条件

    • 有继承关系
    • 子类重写父类方法
    • 父类引用指向子类对象
  • 注意事项

    • 多态是方法的多态,属性没有多态性
    • 父类和子类,有联系,类型转换异常! ClassCastException !
    • 存在的条件:继承关系,方法需要重写,父类指向子类对象!Fathor f = new Son();
    public static void main(String[] args) {
        //一个对象的实际类型是确定的
        Student student = new Student();
        Person person = new Person();
            /*
            可以指向引用类型就不确定了:
                父类的引用指向子类,这就是多态
                不能调用子类的独有方法
             */
            Person stu = new Student();
        Object os = new Student();
        stu.run();
    }
    
  • instanceof (类型转换)引用类型,判断要给对象是什么类型

      public static void main(String[] args) {
          //Object > Person > Student
          Object obj = new Student();
          System.out.println(obj instanceof Student); //true
          System.out.println(obj instanceof Person);  //true
          System.out.println(obj instanceof Object);  //true
          System.out.println(obj instanceof Teacher); //false
          System.out.println(obj instanceof String);  //false
    
          System.out.println("==========");
    
          Person per = new Student();
          System.out.println(per instanceof Student); //true
          System.out.println(per instanceof Person);  //true
          System.out.println(per instanceof Object);  //true
          System.out.println(per instanceof Teacher); //false
          //System.out.println(per instanceof String);  //编译都报错了!
    
          System.out.println("==========");
    
          Student stu = new Student();
          System.out.println(stu instanceof Student); //true
          System.out.println(stu instanceof Person);  //true
          System.out.println(stu instanceof Object);  //true
          //System.out.println(stu instanceof Teacher); //编译报错!
          //System.out.println(per instanceof String);  //编译都报错了!
    
      }
    
  • 类型转换

    • 父类引用指向子类的对象
    • 把子类转为父类,向上转型
    • 把父类转为子类,向下转型,强制转换
    • 方便方法的调用,减少重复的代码!
    //父转子
    public static void main(String[] args) {
        //类型之间转换:父   子
        //高                低
        Person per = new Student();
        per.run();
        //per.go();不可使用
        //将这个对象转换成Student类型,就可以用student类的方法了
        Student stu = (Student) per;
        stu.go();
    }
    //子转父,会丢失子类的方法
    public static void main(String[] args) {
        Student stu = new Student();
        stu.go();
        Person per = stu;
        //per.go();//不可使用
    }
    
    
  • static

    public class Student{
        private static int age; //静态变量 多线程会多用!
        private double score;   //非静态变量
        public void run(){
            System.out.println("run...");
        }
        public static void go(){
            System.out.println("go...");
        }
        public static void main(String[] args) {
            Student stu = new Student();
            System.out.println(stu.score);
            System.out.println(stu.age);
            //System.out.println(Student.score);//不可使用
            System.out.println(Student.age);
    
            //run()://不可调用
            new Student().run();
            go();//可以用
        }
    }
    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();
            /*
            执行顺序
                1.静态代码块
                2.匿名代码块
                3.构造器
             */
        }
    }
    /*
    静态导入包
     */
    import static java.lang.Math.random;
    import static java.lang.Math.PI;
    public class Test {
        public static void main(String[] args) {
            //System.out.println(Math.random());
            System.out.println(random());
            System.out.println(PI);
        }
    }
    /*
    被final修饰的类就断子绝孙了...
    被final修饰的基本变量必须有初始值,且不可更改
    被final修饰的引用变量不能在指向其他对象
    */
    

抽象类和接口

抽象类

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

    //abstract 抽象类: 类,extends 单继承~  接口可以多实现
    public abstract class Action {
        /*
        abstract 抽象方法,只有方法名,没有方法的实现!
        约束,帮我们实现
         */
        public abstract void doSomething();
        /*
        1.不能new抽象类,只能开子类去实现:约束!
            new的话编译报错:'Action' 是抽象的;无法实例化
        2.抽象类中可以写普通方法
        3.抽象方法必须在抽象类中
        
        抽象的抽象:约束
        思考题? 存在构造器吗?
        存在的意义 抽象出来~ 提高开发效率
         */
    }
    /*
    抽象类的所有方法,除非子类也是抽象类,否则继承了他的子类都要实现他的方法~
     */
    public class A extends Action{
        @Override
        public void doSomething() {
    
        }
    }
    

接口

  • 比较

    • 普通类,只有具体实现
    • 抽象类,具体实现和规范(抽象方法)都有!
    • 接口,只有规范!自己无法写方法~专业的约束!约束和实现分离:面对接口编程
  • 接口就是规范,定义的是一组规则,体现了现实世界中 "如果你...则必须能...的思想"

    • 如果你是天使,则必须能飞。如果你是汽车,则必须能跑。如果你好人,则必须干掉坏人;如果你是坏人,则必须欺负好人
  • 接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守

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

    //抽象的思维~ Java
    //关键字 interface
    public interface UserService {
        //常量~ public static final
        int AGE = 99;
        //接口中的所有定义的方法都是抽象的 public abstract
        void add(Long id);
        void delete(Long id);
        void update(Long id);
        void query(Long id);
    }
    public interface TimeService {
        void timer();
    }
    /*
    类可以实现接口 implements 接口
    实现了接口的类,就需要重写接口中的方法~
    多实现~利用接口实现多继承
     */
    public class UserServiceImpl implements UserService,TimeService{
        @Override
        public void add(Long id) { }
        @Override
        public void delete(Long id) { }
        @Override
        public void update(Long id) { }
        @Override
        public void query(Long id) { }
        @Override
        public void timer() { }
    }
    
  • 作用

    • 约束
    • 定义一些方法,让不同的人实现
    • 接口都是public abstract
    • 常量都是public static final
    • 接口不能被实例化,接口中没有构造方法
    • 接口可implements多个,必须重写接口中所有的方法

内部类及OOP实战

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

    public class Outer {
        private int age = 10;
        public void out(){
            System.out.println("这是外部类方法");
        }
    
        public class Inner{
            public void in(){
                System.out.println("这是内部类方法");
            }
            public void getAge(){
                System.out.println(age);
            }
        }
    }
    public static void main(String[] args) {
        Outer outer = new Outer();
        //通过这个外部类来实例化内部类~
        Outer.Inner inner = outer.new Inner();
        inner.in();
        inner.getAge();//10
    }
    
    //如果内部类加修饰词static成为静态内部类
    public static class Inner{
        public void getAge(){
            //System.out.println(age);编译都出错了,static实例化在age之前所以拿不到age了。除非age也成为静态变量
        }
    }
    
    /*
    一个java类中可以有多个class类,但是只能由一个 public 修饰的 class
     */
    public class Outer {
    }
    class A{
    }
    
    //写在外部类方法中的类就是局部内部类
    public class Outer {
        public void method(){
            class Inner{
                public void in(){
                    System.out.println("局部内部类");
                }
            }
        }
    }
    
    /*
    匿名内部类的更多实现
     */
    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("1");
        }
    }
    interface UserService{
        void hello();
    }
    
  • 思想很重要!!!

猜你喜欢

转载自www.cnblogs.com/liuzd-2020/p/13404678.html