Java 面向对象

发布时间 2024-01-01 22:35:40作者: 初夏如霞

面向对象的定义

  • 面向过程的思想:
    • 步骤清晰简单,第一步做什么,第二步做什么...
    • 面向过程适合处理一些较为简单的问题
  • 面向对象思想:
    • 物理类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思考。
    • 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
  • 对于描述复杂的事物,为了从宏观上把控,从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观的操作,仍然需要面向过程的思路去处理。
  • 面向对象编程(OOP)本质是:以类的方式组织代码,以对象的组织(封装)数据。
  • 面向对象三大特性:
    • 封装
    • 继承
    • 多态
  • 从认识论角度考虑是先有对象后有类。对象,是具体的事物;类,是对对象的抽象。
  • 从代码运行角度来说是先有类后有对象,类是对象的模板。

类和对象

  • 类和对象的关系举例来说就是狗是一个类,而旺财是对象,即类是一种抽象的数据类型,而对象是具体概念的具体实例。

  • 创建对象:

    • 使用 new 关键字创建对象

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

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

      • 必须和类的名字相同
      • 必须没有返回类型,也不能写 void
      public class Application{
      	public static void main(String[] args){
      	
      		Student student1 = new Student();
      		Student student2 = new Student();
      		
      		student1.name = "xiaoming";
      		student2.age = 12;
      	}
      }
      
      //创建类
      public class Student {
      	//属性:字段
      	String name;
      	int age;
      	
      	//方法
      	public void study(){
      		System.out.println(this.name+"在学习");
      	}
      }
      

构造器

  • 一个类即使什么都不写,只要创建类就也会存在一个构造方法。
  • 使用 new 关键字,本质上是在调用构造器。
  • 一旦定义了有参构造,无参构造就必须定义。
  • 构造器用来初始化值。

封装

  • 优点:

    • 封装可以提高程序的安全性,保护数据
    • 隐藏代码的实现细节
    • 统计接口
    • 增加系统的可维护性
  • 属性私有,get/set

    public class Test{
    	public static void main(String[] args){
    		Student s1 = new Student();
    		s1.setName("小明");
    		System.oout.println(s1.getName());
    	}
    }
    
    
    
    
    public class Student{
    	//属性私有
    	private String name;
    	private int id;
    	private char sex;
    	//get 获取这个数据
    	public String getName(){
    		return this.name;
    	}
    	//set 给这个数据设置值
    	public void setName(String name){
    		this.name = name;
    	}
    }
    

继承

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

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

  • Java 中只有单继承,没有多继承。

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

  • 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字 extends 来表示

  • 子类继承了父类就可以使用父类的全部方法。

    public class Test{
    	public static void main(String[] args){
    		Student s1 = new Student();
    		s1.say();
    	}
    }
    //构造父类
    public class Person{
    	public void say(){
    		System.out.println("说了一句话");
    	}
    }
    //构造子类
    public class Student extends Person{
    }
    
  • super:用于子类使用父类的方法

    public class Test{
    	public static void main(String[] args){
    		Student s1 = new Student();
    		s1.test("xiaoxiaoming");	//之后会分别输出 xiaoxiaoming xiaoming ming
    	}
    }
    //构造父类
    public class Person{
    	protected String name = "ming";
    }
    //构造子类
    public class Student extends Person{
    	privated String name = "xiaoming"
    	public void test(String name){
    		System.out.println(name);	//打印输入的 name 参数
    		System.out.println(this.name);	//打印子类的 name 参数
    		System.out.prinyln(super.name);	//打印父类的 name 参数
    	}
    }
    
    • super 必须只能出现在子类的方法或者构造方法中
    • super 和 this 不能同时调用方法。
    • super 代表父类对象的应用,只能在继承条件下使用;this 代表本身调用者这个对象,没有继承条件也可以使用。
  • 方法重写

    • 重写是方法的重写,与属性无关。

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

      • 方法名必须相同
      • 参数列表必须相同
      • 修饰符:范围可以扩大但不能缩小 public>Protected>Default>private
      • 抛出的异常:范围,可以被缩小,但不能扩大: ClassNotFoundException
    • 静态:

      public class Test {
      	public static void main(String[] args){
      		A a = new A();	//方法的调用只和左边,定义的数据类型有关
      		a.test();		//输出为A=>test()
      		
      		B b = new A();	//父类的引用指向了子类
      		b.test();		//输出为B=>test()
      	}
      }
      
      public class A extends B{
      	public static void test(){
      		System.out.println("A=>test()");
      	}
      }
      
      public class B{
      	public static void test(){
      		System.out.println("B=>test()");
      	}
      }
      
    • 非静态:

      public class Test {
      	public static void main(String[] args){
      		A a = new A();	//方法的调用只和左边,定义的数据类型有关
      		a.test();		//输出为A=>test()
      		
      		B b = new A();	//子类重写了父类的方法
      		b.test();		//此时输出为A=>test()
      	}
      }
      
      public class A extends B{
      	//Override 重写
      	@Override //注解:有功能的注释
      	public void test(){
      		System.out.println("A=>test()");
      	}
      }
      
      public class B{
      	public void test(){
      		System.out.println("B=>test()");
      	}
      }
      
    • 静态和非静态差别较大,注意两者的区别

多态

public class Test{
	public static void main(String[] args){
		//一个对象的类型是确定的
		//new Student();
		//new Person();
		
		//但是可以只想的引用类型就不确定了:父类的引用可以指向子类
		Student s1 = new Student();
		Person s2 = new Student();
	}
}
//构造父类
public class Person{
}
//构造子类
public class Student extends Person{
}
  • instanceof (类型转换):用来测试一个对象是否为一个类的实例或者子类实例,语法为:

    boolean result = obj instanceof Class
    // obj是一个对象,Class 表示一个类或者接口。obj 是 Class 类的实例或和子类实例时,结果 result 返回 true,否则返回 false
    
    public class Test{
    	public static void main(String[] args){
    		Person p1 = new Person();
    		Person p2 = new Student();
    		Student s1 = new Student();
    		System.out.println(p1 instanceof Student);	//false 因为p1 是 Person 类,而 Person 不是 Student 的子类
    		System.out.println(p2 instanceof Student);	//true 因为p2 实际为Student 类
    		System.out.println(s1 instanceof Student);	//true 因为 s1 是 Student 的实例
    	}
    }
    //构造父类
    public class Person{
    }
    //构造子类
    public class Student extends Person{
    }
    

static的使用

  • 静态变量和非静态变量

    public class Test{
    	private static int age;	//多线程使用
    	private double source;
    	
    	public static void main(String[] args){
    		System.out.println(Test.age);
    		System.out.println(Test.source);	//报错,因为非静态变量无法直接调用
    		
    		//非静态变量调用方法
    		Test t = new Test();
    		System.out.println(t.source);	//先创建对象再引用对象的非静态变量
    	}
    }
    
  • 静态方法和非静态方法

    public class Test{
    	private static int age;	//多线程使用
    	private double source;
    	
    	public void run(){
    	
    	}
    	
    	public static void go(){
    	
    	}
    	
    	public static void main(String[] args){
    		run();	//报错,无法直接调用非静态方法
    		go();
    		
    		//调用非静态方法
    		new Test().run();	//需要先引用非静态方法所属的类再引入非静态方法
    	}
    }
    
  • 代码块和静态代码块

    public class Test{
    	{
    		//代码块(匿名代码块)
    	}
    	
    	static{
    		//静态代码块,最先执行且执行一次
    	}
    }
    
    public class Test{
    	{
    		System.out.println("匿名代码块");
    	}
    	
    	static{
    		System.out.println("静态代码块");
    	}
    	
    	public Test(){
    		System.out.println("构造方法");
    	}
    	
    	public static void main(String[] args){
    		Test test = new Test();
    		Test test2 = new Test();
    	}
    }
    
    //输出结果依次为:静态代码块 匿名代码块 构造方法
    //第二次输出结果依次为:匿名代码块 构造方法
    

抽象类

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

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

    • 抽象类:不能使用 new 关键词来创建对象,它是用来让子类继承的。
    • 抽象方法:只有方法的声明,没有方法的实现,它是用来让子类实现的。
  • 子类继承抽象类,那么就必须实现抽象类没有实现的抽象方法,否则该子类也要声明为抽象类。

    • 抽象类:

      /* 文件名 : Employee.java */
      public abstract class Employee
      {
         private String name;
         private String address;
         private int number;
         public Employee(String name, String address, int number)
         {
            System.out.println("Constructing an Employee");
            this.name = name;
            this.address = address;
            this.number = number;
         }
         public double computePay()
         {
           System.out.println("Inside Employee computePay");
           return 0.0;
         }
         public void mailCheck()
         {
            System.out.println("Mailing a check to " + this.name
             + " " + this.address);
         }
         public String toString()
         {
            return name + " " + address + " " + number;
         }
         public String getName()
         {
            return name;
         }
         public String getAddress()
         {
            return address;
         }
         public void setAddress(String newAddress)
         {
            address = newAddress;
         }
         public int getNumber()
         {
           return number;
         }
      }
      
    • 继承抽象类:

      /* 文件名 : Salary.java */
      public class Salary extends Employee
      {
         private double salary; //Annual salary
         public Salary(String name, String address, int number, double
            salary)
         {
             super(name, address, number);
             setSalary(salary);
         }
         public void mailCheck()
         {
             System.out.println("Within mailCheck of Salary class ");
             System.out.println("Mailing check to " + getName()
             + " with salary " + salary);
         }
         public double getSalary()
         {
             return salary;
         }
         public void setSalary(double newSalary)
         {
             if(newSalary >= 0.0)
             {
                salary = newSalary;
             }
         }
         public double computePay()
         {
            System.out.println("Computing salary pay for " + getName());
            return salary/52;
         }
      }
      
    • 实例化子类:

      /* 文件名 : AbstractDemo.java */
      public class AbstractDemo
      {
         public static void main(String [] args)
         {
            Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00);
            Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00);
       
            System.out.println("Call mailCheck using Salary reference --");
            s.mailCheck();
       
            System.out.println("\n Call mailCheck using Employee reference--");
            e.mailCheck();
          }
      }
      
  • 抽象方法只包含一个方法名,而没有方法体。抽象方法没有定义,方法名后面直接跟一个分号,而不是花括号。继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。

    • 抽象方法:

      public abstract class Employee
      {
         private String name;
         private String address;
         private int number;
         
         public abstract double computePay();
         
         //其余代码
      }
      
    • 继承子类:

      /* 文件名 : Salary.java */
      public class Salary extends Employee
      {
         private double salary; // Annual salary
        
         public double computePay()
         {
            System.out.println("Computing salary pay for " + getName());
            return salary/52;
         }
       
         //其余代码
      }
      

接口

  • 种类:

    • 普通类:只有具体实现
    • 抽象类:具体实现和规范(抽象方法)都有
    • 接口:只有规范,自己无法写方法,类似于现实世界的“如果你是 xxx,则必须 xxx”
  • 声明类的是 class,而声明接口的是 interface

  • 举例:

    • 建立接口:

      public interface UserService{
      	//接口中如果有也只会有常量不会有变量  public static final
      	int AGE = 99;
      	
      	//接口中所有定义的方法都是抽象的
      	void add(String name);
      	void delete(String name);
      	void update(String name);
      	void query(String name);
      }
      
    • 建立实现子类:

      //类可以通过 implements 关键字来实现接口
      public class User serviceImpl implements UserService {
      	//实现接口的类,必须要重写接口中的方法
      	@Override
      	public void add (String name){
      		
      	}
      	@Override
      	public void detele (String name){
      		
      	}
      	@Override
      	public void update (String name){
      		
      	}
      	@Override
      	public void query (String name){
      		
      	}
      }
      

内部类

  • 指写在类里面的类

    public class Outer{
    	private void out(){
    		System.out.println("这是外部类的方法");
    	}
    	
    	class Inner{
    		public void in(){
    			System.out.println("这是内部类的方法");
    		}
    	}
    }
    
    public class Test{
    	public static void main(String[] args){
    		Outer outer = new Outer();
    		Outer.Inner inner = outer.new Inner(); //引用内部类
    		inner.in();
    	}
    }