1.面向过程与面向对象
面向过程(Procedural Programming)和面向对象(OOP)是两种不同的编程思维,它们有着不同的设计思想和实现方式。
面向过程是将程序的设计和实现建立在过程(或方法)的概念上,程序被组织为一系列方法,更注重于过程的执行,更适合于简单、直接的问题解决
。
面向对象是将程序的设计和实现建立在对象的概念上,将现实世界中的事物抽象为对象,每个对象都有自己的属性(数据)和行为(方法),通过调用每个对象的属性或方法去解决问题
。这样的设计模式使得代码更加模块化、易于理解和维护。
举例来说,大象装进冰箱需要几步?
按照面向过程思想:
第一步:工作人员去打开冰箱门
第二步:把大象塞进冰箱
第三步:工作人员把冰箱门关上
这里我们就看出来了,面向过程就是把一件事按步骤一步一步来实现
用代码表示面向过程
public void openDoor(){} //开门
public void putIn(){} //装冰箱
public void closeDoor(){} //关门
用面向对象思想解决大象装进冰箱
按照面向对象思想:
冰箱作为一个对象;
大象作为一个对象。
冰箱有这些功能:开门、装物体、关门
用代码表示
class fridge{
public void open(大象){} //开门
public void putIn(大象){} //放进冰箱
public void close(大象){} //关门
}
class elephant{
public void eat(){} //吃
}
看出来了什么?每个对象是独立的,有属于它自己的功能,只需要专心实现自己的功能就好。所以在建立对象模型阶段,仅仅关注对象有什么的功能,但不考虑如何实现这些功能。
如果不懂,我再举个例子
例如我们可以把"猫"抽象对象来理解:
- 属性:猫的属性可以是它的颜色、体重、年龄等。
- 行为:猫的行为可以是它的叫声、移动等。
现在让我们用 Java 代码来实现一个简单的猫类:
// 定义猫类
public class Cat {
// 属性
private String color;
private double weight;
private int age;
// 构造方法
public Cat(String color, double weight, int age) {
this.color = color;
this.weight = weight;
this.age = age;
}
// 方法:获取颜色
public String getColor() {
return color;
}
// 方法:获取体重
public double getWeight() {
return weight;
}
// 方法:获取年龄
public int getAge() {
return age;
}
// 方法:猫叫
public void meow() {
System.out.println("喵喵~");
}
// 方法:猫移动
public void move() {
System.out.println("猫在走动");
}
}
// 测试类
public class Main {
public static void main(String[] args) {
// 创建猫对象
Cat myCat = new Cat("橘色", 4.5, 3);
// 访问属性并输出
System.out.println("我的猫的颜色是:" + myCat.getColor());
System.out.println("我的猫的体重是:" + myCat.getWeight() + "kg");
System.out.println("我的猫的年龄是:" + myCat.getAge() + "岁");
// 调用方法
myCat.meow(); // 输出:喵喵~
myCat.move(); // 输出:猫在走动
}
}
在上面的代码中,我们定义了一个 Cat
类,其中包括了猫的属性(颜色、体重、年龄)和行为(叫声、移动)。然后在 Main
类中,我们创建了一个猫的对象 myCat
,并访问了它的属性和调用了它的方法。
这个例子就是面向对象的一个简单示例,通过对象来使得代码更加直观易懂,现在你明白了吗?
2.面对对象基本概念
2.面向对象基本概念
2.1访问修饰符
类修饰符:
private
(私有访问控制符)只能在声明private
(内部)类。[default]
默认,只有在同一个包中才可以访问,子类在其他包中则不可以访问。protected
(保护访问控制符)同一个包中的其他任何类以及任何子类(无论子类是在哪个包中声明的)可以访问。public
(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类。abstract
,将一个类声明为抽象类,没有实现的抽象方法,需要子类提供方法实现。final
,将一个类生命为最终(即非继承类),表示他不能被其他类继承。static
,声明静态内部类,可以提供给外部类访问。
成员变量修饰符:
public
(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问。protected
(保护访问控制符)同一个包中的其他任何类以及任何子类(无论子类是在哪个包中声明的)访问。在子类中可以覆盖此变量。private
(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。final
,最终修饰符,指定此变量的值不能变。static
(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类。transient
(过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量,使该属性不参与序列化。volatile
(易失修饰符)指定该变量可以同时被几个线程控制和修改。
方法修饰符:
public
(公共控制符)。private
(私有控制符)指定此方法只能有自己类等方法访问,其他的类不能访问(包括子类)。protected
(保护访问控制符)同一个包中的其他任何类以及任何子类(无论子类是在哪个包中声明的)进行访问。final
,指定该方法不能被重写(Override,子类继承父类)。static
,指定不需要实例化就可以激活的一个方法。不需要对象即可调用。synchronize
,同步修饰符,在多个线程中,该修饰符用于在运行前,对他所属的方法加锁,以防止多个线程的同时访问,运行结束后解锁。
另外在面向对象中
成员变量:类方法体外的变量,存于堆内存,有默认的初始化值(0,unll),局部变量存在栈空间,无默认值。
局部变量:类方法体内的变量,存于栈内存,无默认值,必须定义赋值后才可以使用,随方法的结束而消失。
实例成员必须通过实例对象调用(非 static 修饰)。
类成员可以通过类/实例对象调用(被 static 修饰)。
用 static 修饰的成员均为类成员,被该类共享(类变量,类方法…)。
2.2 关键字this与super
this
表示调用该方法的对象,方法被哪个对象调用,this就指向谁。
使栈内存中该对象指向堆内存中该对象的成员变量。
public class Student {
private int age;
public void method(int age) {
this.age = age; // 添加 this 关键字,使前一个 age 成为成员变量,再将局部变量 age 赋值过去
}
}
在局部变量和成员变量重名下用来指代成员变量一般多用于set,get方法以及一些设计模式
super
访问指向父类
super.成员变量1 //访问父类成员变量1
super(无参/带参) //访问父类无参或带参构造方法
super.方法() //访问父类无参或带参成员方法
2.3构造方法
用于初始化对象,该方法无返回值(特殊:不能用viod修饰),方法名必须和类名一致
无参构造与带参构造
构造方法用于初始化对象
package Demo;
public class Person {
private String name;
private int age;
// 无参构造
public Person() {
}
// 带参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
System.out.println(new Person().name); //null
System.out.println(new Person("坤坤",20).name); //坤坤
}
}
类中最好创建一个无参构建方法,对后续一些事很方便
2.4方法重载
根据参数不同而调用的方法不同
只针对类型不同也可以用泛型方法实现
重载规则:
方法名必须相同
Java允许重载任何方法(main,构造等等)
例如重载构造方法
public Person() {
}
// 带参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name) {
this.name = name;
}
2.5方法重写
重写父类某个方法(父类方法依旧可以使用super调用),其子类权限>=父类
例如重写toString方法
打印一个对象的时候,会自动调用该对象的toString()方法
@Override
public String toString() {
return name+String.valueOf(age);
}
public class Pet {
String name;
String color;
int age;
// 四个不同的构造方法,这里用到了方法重载
public Pet(String aName, String aColor, int aAge) {
name = aName;
color = aColor;
age = aAge;
}
public Pet(String aName, int aAge) {
name = aName;
color = "white";
age = aAge;
}
public Pet(String aName, String aColor) {
name = aName;
color = aColor;
age = 2;
}
public Pet() {
name = "Amy";
color = "white";
age = 1;
}
//重写toString方法以便格式化输出
public String toString() {
return "name=" + name + " color=" + color + " age=" + age;
}
public static void main(String[] args) {
// 使用不同的构造方法初始化对象,程序会根据参数的不同选择正确的构造方法
Pet pet1 = new Pet("Jack", "black", 2);
Pet pet2 = new Pet("Dam", "purple");
Pet pet3 = new Pet("John", 3);
Pet pet4 = new Pet();
// 打印查看結果,注意:如果沒有重写toString方法,直接打印对象不能打印出对象的状态。
//打印一个对象的时候,会自动调用该对象的toString()方法
System.out.println(pet1);//等价于System.out.println(pet1.toStrng());
System.out.println(pet2);
System.out.println(pet3);
System.out.println(pet4);
}
}
3. OOP三大特性
3.1 封装
封装是指将某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法间接来实现对隐藏数据的操作和访问。
- 将每个成员变量/方法用 private 修饰成私有成员不被外界修改从而提高程序安全性,
- 可以为每个私有变量设置 set,get 方法以让其他类对私有成员进行操作
3.2 继承
特点:
- 只支持单继承,但支持多层继承
- 子类中所有的构造方法都会默认访问父类中无参构造方法(子类中构造方法第一条语句默认为 super() )
- 子类继承父类数据,并且可能会用到父类数据,因此优先初始化父类
继承语法
public.....子类 extends 父类{
}
通过子类对象访问方法时: 先在子类找,若无则在父类中找,若无,则报错
3.3 多态
多态性是面向对象中最重要的概念,在Java中的体现:对象的多态性:父类的引用指向子类的对象
父类类型 变量名 = 子类对象;
例如:
Person p = new Student();
Object o = new Person();//Object类型的变量o,指向Person类型的对象
o = new Student(); //Object类型的变量o,指向Student类型的对象
Java 引用变量有两个类型:编译时类型
和 运行时类型
。编译时类型由 声明
该变量时使用的类型决定,运行时类型由 实际赋给该变量的对象
决定。
简称:编译时,看左边;运行时,看右边。
多态前提
继承或实现接口
无继承不重写
重写(编译看左,执行看右,若不重写则实现父类方法)
若想通过多态调用子类方法,则必须重写父类方法
父类引用指向子类对象/父接口指向子类对象
父类做方法参数值,父类做方法返回值类型
多态的意义
降低代码耦合性,提高代码扩展性
方法重载,重写体现多态,对象体现多态(重,难点)
父类引用指向子类对象(子类引用赋值给父类对象)
常见两种应用:
父类做方法参数类型
public class Person{
private Pet pet;
public void adopt(Pet pet) {//形参是父类类型,实参是子类对象
this.pet = pet;
}
public void feed(){
pet.eat();//pet实际引用的对象类型不同,执行的eat方法也不同
}
}
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
Dog dog = new Dog();
dog.setNickname("小白");
person.adopt(dog);//实参是dog子类对象,形参是父类Pet类型
person.feed();
Cat cat = new Cat();
cat.setNickname("雪球");
person.adopt(cat);//实参是cat子类对象,形参是父类Pet类型
person.feed();
}
}
父类做方法返回值类型
public class PetShop {
//返回值类型是父类类型,实际返回的是子类对象
public Pet sale(String type){
switch (type){
case "Dog":
return new Dog();
case "Cat":
return new Cat();
}
return null;
}
}
public class TestPetShop {
public static void main(String[] args) {
PetShop shop = new PetShop();
Pet dog = shop.sale("Dog");
dog.setNickname("小白");
dog.eat();
Pet cat = shop.sale("Cat");
cat.setNickname("雪球");
cat.eat();
}
}
向上转型(自动类型转换)
//子 -> 父
Fu f=new zi();
能调用子类重写方法,父类本有方法,不能调用子类特有
向下转型(强制类型转换)
存在向上转型前提方可向下转型
//父 -> 子
Zi z=(Zi)f;
通过向下转型可以调用父类/子类方法/子类特有方法
到此为止,java面向对象你已经了解差不多了,后面还有接口,内部类,匿名类等正在等待你的阅读与关注!