Java SE-面向对象

Java SE-面向对象

1、什么是面向对象

  • 面向对象编程(oop):物以类聚,分类的思想模式。就是先把问题分类,再对这些分类问题进行思考,最后才是对分类下的细节进行面向过程处理。

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

  • 抽象:把共同的地方抽取出来(把像的地方抽出来组成类);

  • 三大特性:封装,继承,多态;

  • 认识:从认识论考虑,现有对象后有类。对象是具体的事物,类是抽象的,是对对象的抽象;

  • 实践:从代码的运行角度考虑,现有类后有对象,类是对象的模板。

//对象的创建
public class Student {
   String name;
   double age;

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

}
/*
      Student xiaomao = new Student();//类具体为对象
      Student xiaohong = new Student();

      xiaomao.name = "xiaomao";//为对象赋值
      xiaomao.study();//xiaomao在学习
      xiaohong.study();//null在学习

2、构造函数

  • 构造函数和类名相同,没有返回值,且不能写void

  • 一个类即使什么都不写,都会存在一个构造器

  • new类,本质是在调用构造函数,原来初始化对象的值;根据函数的个数类型,默认调用相应的构造函数,新建对象时,根据调式时步骤,会先去类里调用构造函数,才会生成具体对象

  • alt+insert,自动生成构造函数

  • 如果需要初始化参数个数不同的对象,需要新建多个构造函数;

  • 如果定义了有参构造,必须手动创建一个无参构造函数

    /*构造函数和类名相同,没有返回值,且不能写void
    1、一个类即使什么都不写,都会存在一个构造器
    2、new类,本质是在调用构造函数,原来初始化对象的值
    3、alt+insert,自动生成构造函数
    4、如果需要初始化参数个数不同的对象,需要新建多个构造函数;
    5、如果定义了有参构造,还想创建无参对象,必须手动创建一个无参构造函数
    */
    public class Person {
     String name;
     int age;
    //初始化name
     public Person(String name) {
         this.name = name;
    }
    //初始化age
     public Person(int age) {
         this.age = age;
    }
    //同时初始化name&age
     public Person(String name, int age) {
         this.name = name;
         this.age = age;
    }
    }
    /*
         Person person = new Person("唐",4);//根据函数的个数类型,默认调用相应的构造函数
         Person person1 = new Person("唐");//新建对象时,根据调式时步骤,会先去类里调用构造函数,才会生成具体对象
         Person person2 = new Person(7);//
         System.out.println(person.name);
         System.out.println(person.age);
    */

3、创建对象内存分析

Java SE-面向对象

package opp.demo03;

public class Pet {
   public String name;//公共类才能被引入的包调用,如果同一个包可以不用加public
   public int age;
   public void shout(){
       System.out.println("叫了一会");
  }
}
/*
       Pet dog = new Pet();
       dog.name = "小强";
       dog.age = 3;
       dog.shout();
       System.out.println(dog.age);
       System.out.println(dog.name);
*/

 

4、封装

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

  • 封装:通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息的隐藏。

  • 属性私有:set/get

    public class Student {
     private String name;
     private int age;
     private char sex;
    //私有的参数,需要创建方法来设置(set)和获取(get)它才可以
     public String getName() {
         return name;
    }

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

     public int getAge() {
         if(age ==0){
             System.out.println("设置了非法值");
        }
         return age;
    }

     public void setAge(int age) {
         if(age<=120||age>=0){
             this.age = age;
        }else{
             this.age = 0;
        }

    }

     public char getSex() {
         return sex;
    }

     public void setSex(char sex) {
         this.sex = sex;
    }
    }
    /*
         Student s1= new Student();
         s1.setName("张三");
         s1.setAge(999);//一看这里的年龄就不会,学生年龄不可能有999岁,可以在设置年龄的方法里面加限制条件
         System.out.println(s1.getName());
         System.out.println(s1.getAge());
    */

5、继承

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

  • extends意思是扩展,子类是父类的扩展,私有的参数无法被直接调用,私有的方法无法被继承;

  • Java中只有单继承,没有多继承;(儿子只能有一个爸爸或是爷爷,爸爸可以有几个儿子...)

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

  • 子类和父类之间,从意义上讲是“is a”关系,如:旺财是一只狗

  • 所有类都会继承object类(object类可以说是老祖宗,一脉单传)

  • super (重点)

  • 方法重写 (重点)

    import opp.demo05.Student;
    import opp.demo05.Teacher;

    public class Application {
       public static void main(String[] args) {
           Student student = new Student();
           Teacher teacher = new Teacher();
           student.say();
           teacher.say();
      }
    }
    /*
    public class Person {
       private int money = 10_0000_0000;

       public int getMoney() {
           return money;
       }
       
       public void setMoney(int money) {
           this.money = money;
       }
       
       public void say(){
           System.out.println("会说话");
       }

    }

    public class Student extends Person{

    }

    public class Teacher extends Person{

    }

    */

6、Super

  1. super调用符类的构造方法,必须在构造方法的第一个

  2. super必须只能出现在子类的方法或者构造方法中;

  3. super和this不能同时调用构造方法;

  代表对象不同 前提 构造方法
super 代表父类对象的应用 只能在继承条件下才可以使用 父类的构造
this 本身调用者这个对象 没有继承也可以使用 本类的构造
import opp.demo05.Student;
import opp.demo05.Teacher;

public class Application {
   public static void main(String[] args) {
       Student s1 = new Student();
       s1.test();
  }
}
/*
public class Person {
   public Person(String name) {
       System.out.println("Person无参构造函数被调用");
   }


   protected String name = "人类";
   //私有的方法不能被继承,改为私有,子类的super.print()方法会出错
   public void print(){
       System.out.println("Person");
   }
}
/————————————————————————————————————————————————————————————————————————————
public class Student extends Person{
   public Student() {
       //隐藏了一个代码:super();自动调用父类的构造器,必须放在子类构造器的第一行

       super("hello");//
       //this("hello");//调用自己的构造函数,构造函数里不能同时调用自身的构造函数和父类构造函数
       System.out.println("Student的无参构造函数被调用了");
   }

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

   private String name = "学生";
   public void print(){
       System.out.println("Student");//起名,调用的是本方法的参数
   }
   public void test(){
       print();
       this.print();
       super.print();
   }
}

*/

7、方法重写

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

  • 方法名必须相同;

  • 参数列表必须相同;

  • 修饰符:范围可以扩大但不能缩小,public->Protected->Default->private

  • 抛出的异常:范围可以缩小,但是不能扩大:ClassNotFoundException--->Exception(范围大)

  • 重写,子类的方法和父类的必须一致,方法体不同

  • 为什么要重写方法:1、父类的功能子类不一定需要,或者不一定满足;2、Alt+Insert快捷键,选择override;

import opp.demo06.B;
import opp.demo06.A;
//非静态方法和静态方法有很大的区别
public class Application {
   public static void main(String[] args) {
      //静态方法:方法的调用只和左边定义的引用类型有关
       //非静态方法:跟调用创建的对象有关
       B b = new B();
       b.test();
      //父类的引用指向子类b
       A a =new B();//重写非静态的方法,关键字必须是public才可以重写
       a.test();//重写后都是等于

  }
}

public class B extends A{
   //重写
   @Override//注释,有功能的注释
   public void test() {
       System.out.println("Btest");
  }
}

public class A {
   public void test(){
       System.out.println("Atest");
  }
}

8、多态

注意事项

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

  • 父类和子类之间有联系才能强制转换类型;ClassCastException!

  • 多态存在条件:1、有继承关系;2、方法需要重写;父类的引用指向子类对象!father f1 = new son();

不能重写的有:1、static 方法,属于类,不属于实例;2、final常量;3、private方法,私有的

//多态:有继承关系,且重写了父类的方法,对象调用重写后的方法才会出现多态
public class Application {
   public static void main(String[] args) {
       //一个对象的实际类型是确定的
       //可以指向的引用类型就不确定了,父类的引用可以指向子类,祖父类的引用也可以指向子类
       //Student能用的方法都是自己的或是父类的
       Student s1 = new Student();
       //当引用为Person父类时,可以指向子类,但是不能调用子类独有的方法
       Person s2 = new Student();
       Object s3 =new Student();
       //对象能执行哪些方法,主要看对象左边类型,和右边关系不大!
       s1.run();//子类继承父类的全部方法
       s2.run();//
       s1.eat();
       //s2.eat();//当引用为Person父类时,可以指向子类,但是不能调用子类独有的方法
      ((Student)s2).eat();//强制转换为子类后可以调用子类的方法
  }
}
/*
public class Person {
   public void run(){
       System.out.println("run");
   }
}


public class Student extends Person{
   //重写了父类的run()方法
   @Override
   public void run() {
       System.out.println("test");
   }

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



*/

9、instanceof和类型转换

  • 这个关键字的用法是:A instanceof B ,返回值为boolean类型,用来判断A是否是B的实例对象或者B子类的实例对象,A和B是否为父子关系,爷孙关系。如果是则返回true,否则返回false。

import opp.demo07.Person;
import opp.demo07.Student;
import opp.demo07.Teacher;
// instanceof :这个关键字的用法是:A instanceof B ,
// 返回值为boolean类型,用来判断A是否是B的实例对象或者B子类的实例对象。
// 如果是则返回true,否则返回false。
public class Application {
   public static void main(String[] args) {
       //Object>String
       //Object>Person>Teacher
       //Object>Person>Student
       System.out.println("===============================");
       Object s1 = new Student();//引用了一个object指向Student
       System.out.println(s1 instanceof Student);//结果为ture
       System.out.println(s1 instanceof Person);//结果为ture
       System.out.println(s1 instanceof Object);//结果为ture
       System.out.println(s1 instanceof Teacher);//结果为false
       System.out.println(s1 instanceof String);//结果为false

       System.out.println("===============================");
       Person s2 = new Student();//引用了一个object指向Student
       System.out.println(s2 instanceof Student);//结果为ture
       System.out.println(s2 instanceof Person);//结果为ture
       System.out.println(s2 instanceof Object);//结果为ture
       System.out.println(s2 instanceof Teacher);//结果为false
       //System.out.println(s2 instanceof String);//编译失败,s2跟String类无关系

       System.out.println("===============================");
       Student s3 = new Student();//引用了一个object指向Student
       System.out.println(s3 instanceof Student);//结果为ture
       System.out.println(s3 instanceof Person);//结果为ture
       System.out.println(s3 instanceof Object);//结果为ture
       //System.out.println(s3 instanceof Teacher);//编译失败,s3跟Teacher类无关系
       //System.out.println(s3 instanceof String);//编译失败,s3跟String类无关系

  }
}

类型转换

  • 父类引用指向子类对象

  • 把子类转为父类,向上转型

  • 把父类转换为子类,向下转型:强制转换

  • 方便调用,减少重复代码,代码简洁

public class Application {
   public static void main(String[] args) {
       //1、类型之间的转换: 父 >子 强制转换 ||| 子 >父   直接转换
       //高             低   ==低转高
       Person s1 = new Student();//直接把子类对象转为父类了,可能会丢失一些子类自己的方法
       //高转低强制转换
      ((Student)s1).go();//强制把父类的对象转为子类,才能调用子类方法,懒得去写父类的代码了

     
  }
}

10、Static小结

  • 静态变量,内存里面只有一个,可以直接调用。 多线程!

  • 非静态方法里面可以直接调用静态方法

  • 非静态的方法不能直接调用,要在main方法里面创建对象才能被调用

  • 整个程序静态代码只运行一次,不管新建几个对象都只执行一次。其他都是按对象创建个数执行

  • 静态引入,直接调用;如:import static java.lang.Math.random;

  • 类被final定义了,则不能被继承

public class Student {
   private static int age;//静态变量,内存里面只有一个,可以直接调用。 多线程!
   private double score;//非静态变量

   public void run(){
      go();//非静态方法里面可以直接调用静态方法
  }
   public static void go(){

  }

   public static void main(String[] args) {
       Student s1 = new Student();
       System.out.println(s1.score);//
      // System.out.println( Student.score);//编译出错,非静态变量不能直接调用
       System.out.println( Student.age);
       System.out.println( s1.age);
       //run();//非静态的方法不能直接调用
       go();//静态的方法可以直接调用
  }
}
public class Person {
  {
       System.out.println("匿名代码块");
  }
   //整个程序静态代码只运行一次,不管新建几个对象都只执行一次。
   // 其他都是按对象创建个数执行
   static{
       System.out.println("静态代码块");
  }

   public Person() {
       System.out.println("构造代码块");
  }

   public static void main(String[] args) {
       new Person();//第一次先执行静态代码块,匿名代码块,构造代码块;
       System.out.println("=============");
       Person s1 = new Person();//第二次先执行匿名代码块,构造代码块;
  }
}
import static java.lang.Math.random;//静态引入
public class Test {
   public static void main(String[] args) {
       System.out.println(random());//直接调用
  }
}

11、抽象类

  • 不能new抽象类,只能靠子类去实现它

  • 抽象类中可以写普通方法

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

  • 抽象类存在构造器吗?因为抽象类不可实例化,那么只能在子类实例化时调用该抽象类的构造器才有用

  • 父类是抽象类,子类是一般类,那么子类需要重写父类中的抽象方法

  • 父类是抽象类,子类也是抽象类,那么父类的抽象类可以不用重写

//抽象类中可以有抽象的方法和一般方法,但是抽象方法一定要在抽象类中
//父类是抽象类,子类是一般类,那么子类需要重写父类中的抽象方法
//父类是抽象类,子类也是抽象类,那么父类的抽象类可以不用重写
public abstract class Person {
   //抽象方法,只有抽象名,没有具体的实现,需要子类去实现
   public abstract void run();

   public Person() {
       System.out.println("无参构造");
  }
/*
1、不能new抽象类,只能靠子类去实现它
2、抽象类中可以写普通方法
3、抽象方法必须写在抽象类中
4、抽象类存在构造器吗?因为抽象类不可实例化,那么只能在子类实例化时调用该抽象类的构造器才有用
*/
}

public class Test extends Person{
   public Test(){
      super();
  }

   @Override
   public void run() {

  }

   public static void main(String[] args) {
       Test test = new Test();

  }
}

12、接口

  • 接口:只有抽象的方法,无法自己写方法;接口的本质是契约,类继承接口后,需要按接口里面的方法规则去实现方法;接口中一般不放常量;

  • 接口的目的:架构师定义接口名,程序员实现创建了实现接口

  • 接口类标志:interface,接口类只有方法名,不写实现方式;

  • 类可以继承多接口,实现接口的类,需要重写接口中的方法;

/*
1、接口类标志:interface
2、接口类只有方法名,不写实现方式;
3、
*/
public interface UserService {
   public void Update();
   public void Delete();
   public void Query();
   public void run();
}
public interface TimerService {
   public void Timer();
}
/*
1、接口可以实现多继承
2、实现接口的类,需要重写接口中的方法
3、
*/
public class UserServiceImpl implements UserService,TimerService{
   @Override
   public void Timer() {

  }

   @Override
   public void Update() {

  }

   @Override
   public void Delete() {

  }

   @Override
   public void Query() {

  }

   @Override
   public void run() {

  }
}

13、内部类

  • 内部类可以直接获取外部类的方法和常量

  • 注意如何创建内部类的对象:

        //如何创建内部类,先创建外部类对象
       Outer outer = new Outer();
       Outer.Inner inner = outer.new Inner();
public class Outer {
   int id = 10;
   public void test(){
       System.out.println("外部类测试");
  }
  public class Inner{
       public void run(){
           System.out.println("内部类测试");
      }
       //获得外部类的私有属性,常量和方法
       public void GetId(){
           System.out.println(id);
           test();
      }

  }
}

public class Application {
   public static void main(String[] args) {
       //如何创建内部类,先创建外部类对象
       Outer outer = new Outer();
       Outer.Inner inner = outer.new Inner();
       inner.GetId();
  }
}

 

上一篇:【SE】多线程-02


下一篇:Java SE学习笔记的内容目录