Java面向对象

1. 什么是面向对象

先说下面向对象的思想:
之前有面向过程,思想是按步骤一步一步来,先做什么再做什么。
后来问题越来越复杂,面向面向过程不再适合,于是出现了将事物分类的思维模式。
物以类聚,分类的思维模式,会考虑事物需要哪些分类,然后对这些分类进行单独思考,这就是我们说的类Class。最后,才对某个分类下的细节进行面向过程的思索。
面向对象适合处理复杂的问题,适合处理需要多人协作的问题。

面向对象编程(OOP)的本质:将事物描述为类,将内部数据封装为对象,使用类和对象去做对应的事情。

1.1 类和对象

类是一种抽象的数据类型,它是对某一类事物的整体描述和定义,

  • 动物、植物、手机、电脑…
  • Person类、Pet类、 Car类等, 这些类都是用来描述/定义某一类具体的事物应该具备的特点和行为

对象是抽象概念的具体实例

  • 张三就是人的一个具体实例,旺财就是狗的一个具体实例。
  • 能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
  • 必须先设计类,才能获得对象。

1.2 对象和类的创建

定义类:

public class 类名{
	成员变量(代表属性)
	成员方法(代表行为)
}

class Cat(){
	//定义Cat的两个属性
	String name;
	int age;
	//定义Cat的一个行为
	public eat(){
	System.out.println(this.name);
	}
}

创建对象:

//创建一只猫的对象
Cat cat1 = new Cat();
//输出cat1的特征
cat1.name = "小花";
//调用cat1的行为
System.out.println(cat1.eat());

注意:

  • 类名首字母要大写、英文、有意义,满足驼峰模式,不能用关键字
  • 一个外码文件中可以定义多个类,但是只能有一个类是public修饰的
  • 成员变量一般无需指定初始化值,存在默认值。
  • 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化
    以及对类中构造器的调用。
    在这里插入图片描述

成员变量和局部变量

成员变量是指类中方法外的变量,局部变量是指方法中定义的变量。
具体的区别:
在这里插入图片描述

public class Student{
	private String name;	//成员变量
	
	public void study(){
		int i = 0;	//局部变量
		System.out.println(”局部变量“ + i);
	}
}

1.3 构造器

类的构造器也叫构造方法,我们就是通过 new 调用了类的构造方法,构造方法就是创建类对象的方法。每个类都有构造方法,在创建对象的时候,由虚拟机自动调用,给成员变量进行初始化。

构造器的特点:

  1. 必须和类名相同
  2. 没有返回类型(连void都不用写)
  3. 如果构造方法有参数,那么在调用构造方法的时候就需要传入参数
  4. 如果类中没有写构造方法,编译器就会给一个默认的构造方法。如果有就不再给默认的。
public class Car {
	private String brand;
	private String color;
	/**
	* 构造方法
	*/
	public Car(){
		System.out.println("执行了car的构造方法");
	}
	/*有参构造*/
	public Car(String str){
		System.out.println("执行了car的构造方法");
	}

	/**
	* 实例方法/成员方法
	*/
	public void Car() {
	}
}

Car car1 = new Car();	//调无参
Car car1 = new Car("a");	//调有参

构造方法的重载

构造方法可以重载。
有时,我们需要不带全部参数的构造方法,在类中可以构成构造方法的重载:

public class Car {
	private String brand;
	private String color;
	/**
	* 带全部参数的构造方法
	* @param brand
	* @param color
	*/
	public Car(String brand,String color) {
		this.brand = brand;
		this.color = color;
	}
	/**
	* 只有一个参数的构造方法
	* @param brand
	*/
	public Car(String brand) {
		this.brand = brand;
	}

	public Car() {
		
	}
}

javaBean规范: 任何一个标准的javaBean都应该无参数的构造方法。 所以如果我们给一个类显式的指定了有参数的构造方法,那么建议也显式指定出无参数的构造方法。

1.4 private和this关键字

private关键字是一个权限修饰符,可以修饰成员变量和成员方法,被private修饰的成员只能在本类中访问。所以针对private修饰的成员变量,其他类需要使用的话需要提供相应的操作,所以在javaBean对象中提供setXxx(参数)和getXxx()方法来操作成员变量。

this关键字用于引用当前对象,它可以类的成员方法或构造器中访问对象的属性和其他成员方法。当在类的成员方法或构造器中需要引用当前对象时,可以使用this关键字。例如,如果类中有一个与局部变量同名的成员变量,可以使用this来明确指定访问的是成员变量而不是局部变量。

public class Student{
	private String name;
	private int age;
	private intsex;
	
	//用于给成员变量赋值
	public void setAge(int age){
		this.age = age;	// 前面的age是成员变量的值,后面的age是局部变量的值
	}

	//用于获取成员变量的值
	public int getAge(){
		return age;
	}
}

2. 面向对象的特点

2.1 抽象的概念

抽象性指将具有一致的数据结构(属性)和行为(操方法的对象抽象成类,对象是具体的,类是抽象的,是对对象的抽象

2.2 三大特性

1、封装

概念:
封装也叫信息隐藏,将数据和基于数据的操作封装在一起,也叫作对对象和类的封装。对内隐藏实现的细节,对外提供接口访问。

优点:

  • 专业分工,需要什么,就封装对应的数据没,并提供数据对应的行为。
  • 信息隐藏,外部访问是不知道封装行为的内部实现的。
  • 属性私有,封装对象的属性不会被其他对象修改。
  • 方便,需要的时候直接调用对象方法,降低了学习成本。

2、继承

概念:
一个类继承另一个类,称为子类继承父类,关键字extends。

public class Student extends Person {}
Student 为子类,Person为父类

继承的作用:把子类重复的代码抽取到父类中,子类可以继承,实现代码的复用
特点:

  • 子类继承父类的属性和方法,父类遵循里氏替换原则(开闭原则),对修改关闭,对扩展开放。父类私有属性和构造方法不能被继承。
  • 子类可以写自己特有的属性和方法,实现功能的扩展,也可以重写父类的方法
  • Java只有单继承,没有多继承,一个类只能直接继承一个父类。 一个类可以有多个子类。
  • Object类:是JDK提供的一个类,任何一个java类都会直接或者间接的继承Object类。如果我们定义类一个类没有extends关键字,那么编译器在编译这个源码的时候,就会默认的让这个类继承Object
  • 子类可以直接赋值给父类,子类自己特有的属性和方法将看不见(无法使用),父类赋值给子类需要强制类型转换

子类可以继承父类的内容:

在这里插入图片描述
虚方发表:指的是非private,非static,非final修饰的方法,这些方法在类加载的过程中被加载到虚方法表中,子类会继承虚方法表中的方法,并且添加自己的方法。

在这里插入图片描述

继承中的构造方法

继承中的构造方法是不能被继承的,可以被调用

public class Vehicle {
	private String name;
	public Vehicle() {
		System.out.println("父类无参数的构造方法");
	}
}
public class Car extends Vehicle{
	public Car() {
	super();
		System.out.println("子类无参数的构造方法");
	}
}

子类中通过super()调用父类的无参构造方法,super()要在子类构造方法中的第一行
但是如果父类没有无参数的构造方法,那么子类必须申明构造方法

public class Vehicle {
private String name ;
	//父类没有无参数的构造方法
	public Vehicle(String name) {
		this.name = name ;
		System. out . print1n( "父类无参数的构造方法");
	}
}

子类报错
在这里插入图片描述
子类就必须申明构造方法,而且必须在构造方法的第一行调用父类的构造
在这里插入图片描述
原因:子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类就无法使用父类的数据,子类在初始化之前,一定要调用父类的构造方法先完成父类数据空间的初始化。

super和this的区别

在这里插入图片描述

继承中的重写

所谓方法重写就是在子类重新定义父类的方法。和重载不同的是,在子类中定义一个和父类中方法申明完全相同的方法。

特点:

  • 需要继承关系,子类重写父类的方法
  • 子类方法名和参数列表和父类的相同
  • 修饰符:范围可以扩大但不能缩小: public>protected>default>private
  • 抛出的异常:范围,可以被缩小,但不能扩大; ClassNotFoundException -->Exception(大)
  • 父类的私有方法和静态方法无法被重写(覆盖)。

作用:实现方法的扩展(子类扩展父类的方法)

和重载的区别:

  1. 首先重载和重写都是实现多态的方式,区别是前者是编译时的多态,后者是运行时多态。
  2. 重载是在一个类中,方法名相同参数不同;重写是子类和父类之间的事,子类重写的方法名和参数要与父类的一样。
  3. 重载对返回类型没有特殊的要求,重写要求与父类有兼容的返回类型
public class Animal {
//父类中的方法
	public void bark() {
		System.out.println("动物在吼叫!~");
	}
}

public class Cat extends Animal{
//重写父类的方法
	public void bark() {
		System.out.println("小猫在喵喵叫~~~");
	}
}
/*测试*/
Cat cat = new Cat();
cat.bark();//小猫在喵喵叫~~~
//将子类对象赋值给父类引用
Animal a1 = cat;
a1.bark();//小猫在喵喵叫~~~

当我们创建一个子类的对象时,无论是将这个子类当作父类看还是当子类看(父类引用或者子类引用),这个方法执行的永远是子类中的方法。 因为子类覆盖了父类的方法。这就是重写的作用。

父类和子类之间的转换

Dog dog = new Dog();
Animal a2 = dog;
//强制转换 编译阶段,不会有问题
Cat cat2 = (Cat) a2;

这段运行会报错

Exception in thread "main" java.lang.ClassCastException:com.st.demo1.Dog cannot be cast to com.st.demo1.Cat

当执行强制类型转换的时候,被转换的对象(a2)所对应的对象本身(内存中数据结果)必须是目标类型
(Cat),如果不是那么在转换的时候就会抛出异常"java.lang.ClassCastException:

3、多态

概念:多态是以封装和继承为基础的,多态就是指同意方法根据发送对象的不同表现出来的行为不同。多态就是我们将多个不同的子类当作父类看待,调用相同的方法,产生不同的效果

特点:

  • 有继承关系,子类重写父类
  • 父类引用指向子类对象
public class Animal {
	public void bark() {
		System.out.println("动物吼叫");
	}
}
public class Cat extends Animal {
	public void bark() {
		System.out.println("小猫在喵喵叫~");
	}
}
public class Dog extends Animal{
	public void bark() {
		System.out.println("小狗在汪汪叫~");
	}
}
public class Test {
	public static void main(String[] args) {
		Animal a1 = new Cat();
		Animal a2 = new Dog();
		a1.bark();//小猫在喵喵叫~
		a2.bark();//小狗在汪汪叫~
	}
}

a1和a2 都是Animal类型,但是bark方法表现的形态是不一样的。这就是多态

多态是方法的多态,属性没有多态
静态方法,属于类,不属于实例,不能重写,还有final常量,私有方法,不能被重写,更谈不上多态

2.3 抽象类

概念:被abstract修饰符修饰的类就叫抽象类,同样修饰的方法就是抽象方法。

特点:

  1. 抽象类可以没有抽象方法,但是有抽象方法的类一定是抽象类。
  2. 抽象类和抽象方法是为了让子类继承并实现的
  3. 子类继承抽象类就必须实现抽闲类没有实现的抽象方法,否则子类也得声明为抽象类。
  4. 抽象类不能实例化对象(创建对象)
  5. 抽象类就是要被别的类继承,也可以继承其他的类(抽象类和非抽象类),如果一个抽象类继承了另外一个抽象类,那么这个抽象可以选择性的实现父类的抽象方法
  6. 抽象类中可以定义非抽象方法和成员

什么样的类应该什么为抽象类?

如果父类中的一个方法,一定会被子类重写,那么父类中方法的实现(方法体)就没有意义。
如果子类都要自己重写父类的方法,那么父类定义这个方法的意义何在?

为了调用子类的方法,父类定义方法是有意义的,但是方法体是没有意义的,所以我们可以将方法定义为抽象方法,
删除方法体。这样可以提高开发效率,

抽象方法

特点:

  1. 抽象方法必须写在抽象类或者[接口]中
  2. 抽象方法是没有方法体的,也不能写方法体
  3. 抽象方法不能使用static修饰,不能被final修饰,不能被private修饰
  4. 抽象方法可以重载

static修饰的方法可以是用类名直接调用,抽象方法在自己所在的类当中肯定是没有方法体的,不可能正常执行的。 所以不存在静态的抽象方珐

抽象方法只有被子类实现之后才有被调用的意义。否则没有意义,定义为private的方法不能被子类继承实现,
所以不能定义为private。

public abstract class Animal {
	//抽象方法
	public abstract void test();
}

2.4 接口

定义:被interface修饰的类就叫做接口,接口就是定义规范

public interface test{
}

特点:

  1. 接口只有规范,无法实现,定义方法,供别人实现
  2. 所有的成员变量默认都是常量
  3. 接口不能被实例化,没有构造方法
  4. 接口中的方法都是抽象的,JDK1.8开始 接口中可以定义默认方法,而默认方法是非抽象方法
  5. 通过implements关键字实现接口,接口是可以实现多个的(implements A,B,C)
  6. 接口的子类(实现类),要么重写接口的所有抽象方法,要么是抽象类
public class Hello extends Test implements Test1, Test2{
	public void show() {
		System.out.println("123");
	}
}

一个非抽象类实现了一个接口,则这个类必须实现这个接口中的所有非默认方法。
一个抽象类实现了一个接口,可以选择性实现接口中的非默认方法。
默认方法就相当于被继承了,可以直接使用。
默认方法也可以被重写

3. 内部类

所谓内部类就是在一个类中再定义一个类。

内部类分为:成员内部类,局部内部类,静态内部类、匿名内部类。

3.1 成员内部类

成员内部类是申明在类的成员位置的内部类。,其有分为非静态成员内部类和静态成员内部类。

1、 非静态成员内部类

public class Outer {
	private String name;
	public void method() {
		System.out.println("外部类的非静态成员方法");
	};
	public static void stMethod() {
		System.out.println("外部类的静态成员方法");
	}
	//非静态成员内部类
	public class Inner{
		private int age;
		public void innerMethod() {
		System.out.println("内部类的非静态成员方法");
	}
	//非静态内部类中不能申明静态方法
	// public static void innerStMethod() {
		// System.out.println();
	// }

如果要创建内部类的对象,则必须先创建外部类对象

public static void main(String[] args) {
	//首先创建外部内对象
	Outer outer = new Outer();
	//使用外部内对象创建内部类对象
	Outer.Inner inner = outer.new Inner();
	//使用匿名对象
	Inner inner1 = new Outer().new Inner();
	inner.innerMethod();
}

在非静态内部类中不能申明静态方法。
在非静态的内部类中不能申明静态的成员变量,但是可以申明常量。
在内部类中可以访问外部类的所有成员
在非静态成员内部类中可以调用所有的外部类方法
在非静态成员内部类中使用外部类的this的时候,语法是:外部类类名.this。

2、 静态成员内部类

public class Outter {
	//静态成员内部类
	public static class Inner{
		private String name;
		public void method() {
			System.out.println("内部类的非静态方法");
		}
		public static void stMethod() {
			System.out.println("内部类的静态方法");
		}
	}
}

创建静态内部类对象

public static void main(String[] args) {
	//创建静态内部类对象不需要外部类对象
	Outter.Inner inner = new Outter.Inner();
	inner.method();
	//直接调用静态成员内部类的静态方法
	Outter.Inner.stMethod();
}

静态内部类中可以申明静态和非静态的方法和成员变量。
静态内部类中可以调用外部类的任何静态的成员变量和方法,但是不能调用任何非静态的方法和变量,更不能使用外部类的this对象

3.2 局部内部类

概念:申明在类的代码块中的类就是局部内部类。

public class Outter {
	public void method() {
		System.out.println("外部类的成员方法");
	}
	class Inner{
		private String name;
		public void method() {
			System.out.println("局部内部类的方法");
		}
	}
	//局部内部类的使用访问就是这个方法
	Inner inner = new Inner();
	inner.method();
	}
	public static void main(String[] args) {
		Outter outer = new Outter();
		outer.method();

要求:

  • 局部内部类的使用范围就是局部范围,就是申明的范围内。
  • 局部内部类无法使用任何访问修饰符修饰,也不能修饰为static

局部内部类访问外部类:

  • 在局部内部类中可以访问外部类的任何成员。可以使用外部类的this对象等等。
  • 在局部内部类中如果要使用外部类的局部变量,如果jdk是1.7之前,则局部变量必须是final修饰的,1.7之后就不需要了,其实就是默认就是final

3.3 匿名内部类

谓匿名内部类就和匿名对象一样,没有名字。

特点:

  • 常用来直接继承抽象类,或者实现接口。
  • 匿名内部类只能使用一次,不能使用第二次
// 使用匿名内部类实现Runnable接口
new Thread(new Runnable() {
private String name = "runnable";
public void run() {
	System.out.println("匿名内部类实现Runnable接口实现一个线程类");
	System.out.println(name);
	m();//调用外部类的其他成员
}
}).start();

匿名内部类中可以使用外部类的任何成员。
匿名内部类没有任何修饰符。

什么时候使用匿名内部类:

当一个接口或者一个父类申明的抽象方法非常有限,而我们只需要这个类对象一次,这时就使用匿名内部类创建对象。

补充:抽象内部类

内部类能不能抽象?

可以。

  1. 成员非静态内部类可以是抽象类,但是只能被内部类继承,外部类不能继承
  2. 成员静态内部类可以被声明为抽象类,内部和外部类都能继承
  3. 局部内部类可以声明为抽象类,
  4. 匿名内部类不能声明为抽象类
  5. 接口中可以申明:内部接口,成员内部类,局部内部类。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值