面向对象编程OOP
1、概念
面向对象最重要的概念是:类和对象。
- 类——是相同事物共同特征的描述,类并不是具体的
- 对象——是真实存在的具体实例
- 类只有一个,对象可以很多个,这样就可以实现描述万千事物了
- 先有类才有对象
定义类
-
格式:
修饰符 class 类名{
}
-
类名首字母大写
-
一个Java文件中可以定义多个类。但是只能有一个类是用public修饰。
-
public修饰的类名必须成为Java代码的文件名称。 实际开发的规范:一个Java代码文件只定义一个类
构造器
-
作用:调用构造器得到一个对象
-
格式:
修饰符 类名 (形参列表){
//执行代码
}
-
注意事项:
如果一个类没有申明任何构造器,默认会自动一个无参数构造器
如果一个类自己定义了有参数构造器,那么默认的无参数构造器就消失了。如果此时还想要无参数构造器,就必须自定义无参数构造器
this关键字
- this代表当前对象的引用
- 可以出现在构造器和方法中
- 在构造器中表示正在初始化的对象
- 在方法中表示调用方法的对象
- 可以访问对象的成员变量,可以区分成员变量是局部的还是对象中的
封装
- 面向对象的三大特征:封装、继承、多态
- 成员变量一般私有,方法一般暴露,一般要给私有的成员变量一套getter/setter方法进行取值/赋值
- 封装提高了代码安全性和组件化
2、static关键字
-
static == 静态 == 修饰的成员(方法或变量)属于类本身
-
按照有无static修饰,成员变量和方法可以分为:
成员变量:
(1)静态成员变量(类变量):有static修饰的成员变量称为静态成员变量也叫类变量,属于类本身的,直接用类名访问,也可用类的对象访问但不建议。
(2)实例成员变量:无static修饰的成员变量称为实例成员变量,属于类的每个对象的,必须用类的对象来访问
成员方法:
(1)静态方法:有static修饰的成员方法称为静态方法也叫类方法,属于类本身的,直接用类名访问
(2)实例方法:无static修饰的成员方法称为实例方法,属于类的每个对象的,必须用类的对象来访问
3、成员变量和成员方法的访问
静态成员变量访问:
- 类名.静态成员变量
- 对象.静态成员变量(不建议)
实例成员变量访问:
-
先创建对象
-
对象.实例成员变量
静态方法访问:
- 类名.静态方法
- 对象.静态方法(不建议)
实例方法访问:
- 先创建对象
- 对象.实例方法
拓展面试题:
(1)静态方法中是否可以直接访问静态方法? 可以的,都属于类可以直接访问的
(2)静态方法中是否可以直接访问实例方法? 不可以的,实例方法属于对象必须用对象访问
(3)静态方法中是否可以直接访问静态成员变量? 可以的,都属于类,可以直接访问
(4)静态方法中是否可以直接访问实例成员变量? 不可以的,实例成员变量属于对象必须用对象访问
----------------------------------------------------------------
(1)实例方法中是否可以直接访问静态方法? 可以的,静态方法可以被共享
(2)实例方法中是否可以直接访问实例方法? 可以的,因为他们都属于对象,在同一个对象中是可以访问的
(3)实例方法中是否可以直接访问静态成员变量? 可以的,静态成员变量可以被共享
(4)实例方法中是否可以直接访问实例成员变量? 可以的,因为都属于对象,可以访问
4、继承
①概述
-
继承(is a)是子类到父类的一种关系。被继承的类:父类;继承父类的类:子类
-
格式:
子类 extends 父类{
}
-
作用:可以提高代码的复用——相同代码可以定义在父类中子类继承父类就可直接使用
-
继承中子类会比父类更加强大,因为子类出了父类的属性和行为还能自定义其他功能
②子类不能继承的内容
- 确定观点:子类无法继承父类的构造器,子类自己本身也有构造器无需继承。
- 子类可以继承父类的私有成员(变量和方法),但是无法直接访问
- 子类不能继承父类的静态成员(变量和方法),父类只是共享给子类访问,并非继承
③继承后成员变量的特点
-
就近原则:子类有同名变量就优先找子类,否则找父类,父类也没有就报错
public class Demo { public static void main(String[] args) { Student student = new Student(); System.out.println(student.name); // 找子类 CC System.out.println(student.name1); // 找父类 BB // System.out.println(student.name2); // 子类父类都没有就报错 } } // 父类 class People{ public String name = "AA"; public String name1 = "BB"; } // 子类 class Student extends People{ public String name = "CC"; }
-
如果子类要访问父类的成员变量,且有相同的成员变量,会优先使用子类的
-
如果子类一定要访问父类的成员变量,需要使用super关键字
public class Demo02 { public static void main(String[] args) { Student student = new Student(); student.showName(); } } class People{ public String name = "人类"; } class Student extends People{ public String name = "学生"; public void showName(){ String name = "局部名称"; System.out.println(name); // 局部变量 System.out.println(this.name); // 子类的 学生 System.out.println(super.name); // 父类的 人类 } }
④继承后成员方法的特点
- 同成员变量,满足就近原则
⑤方法重写
- 概念:子类继承了父类得到了父类的方法,但是子类不满足父类的方法就自己重写一个同样的方法来覆盖父类的方法
- 要求:
- 子类重写方法的名称和形参列表必须与父类被重写的方法完全一致
- 子类重写方法的访问权限应该与父类一样或更大
- 若父类方法抛出了异常,则子类抛出的异常应该与父类一样或更小
- 方法重写的返回值类型应与父类返回值类型一样或类型范围更小
- 校验注解:@Override 加上注解后必须正确重写父类方法,否则报错
⑥继承后构造器特点
-
继承后,子类的全部构造器一定会先调用父类的无参构造器再执行自己的
-
因为子类构造器第一行有一行隐藏代码super(),调用父类的无参构造器
-
先有爹才有儿
public class Demo { public static void main(String[] args) { Cat cat = new Cat(); Cat cat1 = new Cat("喵喵"); } } //父类 class Animal{ public Animal(){ System.out.println("父类的无参数构造器被执行"); } } //子类 class Cat extends Animal{ public Cat(){ //super(); // 默认存在,调用父类的无参数构造器。 System.out.println("子类的无参数构造器被执行"); } public Cat(String name){ //super(); // 默认存在,调用父类的无参数构造器。 System.out.println("子类的有参数构造器被执行"); } } /* 输出结果: 父类的无参数构造器被执行 子类的无参数构造器被执行 父类的无参数构造器被执行 子类的有参数构造器被执行 */
⑦super调用父类有参构造器
-
子类会在构造器的第一行默认执行super();调用父类无参构造器
-
如果需要调用父类有参构造器需要匹配参数super(参数匹配);
-
把赋值的数据从子类传到父类构造器中去初始化
-
减少代码冗余,提高代码复用
public class Demo { public static void main(String[] args) { Dog dog = new Dog("泰迪", 15); System.out.println(dog.getName()); System.out.println(dog.getAge()); } } //子类 class Dog extends Animal{ public Dog(String name , int age){ super(name , age); } } // 父类。 class Animal{ private String name ; private int age ; public Animal() { } public Animal(String name, int age) { this.name = name; this.age = age; } //getter/setter方法 }
⑧this和super对比
-
this代表当前类对象(子类)
super代表父类对象引用
-
this用在本类中访问本类对象成员:
this.本类成员变量 (可省)
this.本类成员方法 (可省)
this(…) 在本类构造器中访问本类其他构造器,可以借用兄弟构造器来赋默认值。代码如下
super用在本类中访问父类对象成员:
super.父类成员变量
super.父类成员方法
super(…) 在本类构造器中访问父类其他构造器
-
super(…);和this(…);不能同时出现在构造器中,因为都必须在第一行
public class ThisDemo {
public static void main(String[] args) {
// 希望不给学校信息,默认就是北大的
Student s3 = new Student("AA",25 );
System.out.println(s3.getName());
System.out.println(s3.getAge());
System.out.println(s3.getSchoolName());
Student s5 = new Student("BB",24 , "清华大学" );
System.out.println(s5.getName());
System.out.println(s5.getAge());
System.out.println(s5.getSchoolName());
}
}
class Student{
private String name ;
private int age ;
private String schoolName ;
//无参构造器
public Student() {
}
//this(...)访问本类的其他构造器
public Student(String name , int age){
// this(...)借用兄弟构造器功能
this(name ,age ,"北京大学");
}
//有参构造器
public Student(String name, int age, String schoolName) {
this.name = name;
this.age = age;
this.schoolName = schoolName;
}
//getter/setter方法
}
⑨继承的特点
-
Java是单继承的:一个类只能继承一个直接父类
——假如Java可以继承多个类则出现了类的二义性
-
但是一个类可以间接继承多个父类,多层继承
-
一个父类可以有多个子类
-
Java中祖宗类是Object类,一个类要么默认继承了Object类要么间接继承了Object类