1. 什么是面向对象
1.1 面向对象思想
面向对象的思想是一种抽象的思想,它通过将事物模块化,使得复杂的事物能够被模块为简单的事物进行处理,并且通过抽象的方法,在细节处做到更加简洁,面向对象的思想是需要不断学习体会的。
1.2 类与对象
类是一个不实际存在的镜像模板,它是抽象的,也是具体的,它不实际作为操作的对象,但它是我们实际操作的对象的模板。我们通过将类实例化创建对象,再通过类中的属性和方法,对对象进行改变。对象是具体的,实际存在的。
2. 对象的建立
2.1 代码表现
public class Person {
private String name;
private int age;
public void test(){
System.out.println("测试");
}
}
public class Demo01 {
public static void main(String[] args) {
Person XiaoMi = new Person();
Person XiaoCao = new Person();
}
}
我们先建立了一个Person类,这个类中包含了类的属性和方法。我们定义了类的属性有name和age,我们再在main()
方法中通过new
关键字建立实例,这个实例就是具体的对象。
2.2 对象的理解
对象就是类的实例,它可以调用类声明的方法,也具有类定义的属性。
3. 构造器与构造方法
3.1 无参构造器
当我们建立一个实例的对象时,并没有立刻为对象的属性赋值,而是通过无参构造器构造出了具有默认值属性的初始化对象。无参构造器是一段隐藏的方法代码,被称为构造方法。
public Person(){
}//无参构造器
它的本质就是一个方法,但它不会返回值,也不通过void
来声明不返回值。
3.2 有参构造器
有时我们需要使对象的初始化值不为默认值,我们就需要自己创建有参构造器来实现。
public Person(){
this.age = 20;
}//有参构造器
这样我们就能使我们每个创建的对象的age
初始化值都为20,而不是默认的0。
- 构造器的名字必须和类名一致。
- 需要注意的是,即使自己编写了有参构造器,无参构造器还是隐藏存在的。
- 构造器的实现原理是方法,它以方法的形式存在在类中,在建立对象时被调用。
- 无参构造器和有参构造器同时存在,也是一直方法的重载。
4. 封装
我们的程序,会同时存在很多类和方法,为了我们程序的安全性和独立性,我们追求“高内聚,低耦合”,这就要求我们进行封装的处理。
public class Person {
private String name;//通过private修饰词使得属性不能被类的外部调用
private int age;
public void setName(String name) {
this.name = name;
} //通过类内部的public修饰的方法,使得类的外部能对对象的值进行操作,相当于留下一个接口
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
我们通过private修饰词,使得类的属性只能在类的内部访问,再通过public修饰词,使得类的外部,可以获得一个类似接口的方法对对象进行操作,这就是封装的思想,它使得数据更加安全,同时,也更容易对错误进行修改。
5. 继承
有时,我们需要使用A类的属性或者方法到B类中,我们就可以通过extends
使B类继承A类的公开属性和方法,这时A类作为父类,B类作为子类。
extends
只能单继承一个父类,不能多继承多个父类。
5.1 代码表现
public class Student extends Person{
}
}
public class Demo01 {
public static void main(String[] args) {
Person XiaoMi = new Person();
Student XiaoCao = new Student();
System.out.println(XiaoCao.getAge());
}
}
即使Student类中不含有任何元素和方法,我们也可以通过继承Person类的所有元素和方法,直接在Student类中使用。
5.2 super的使用
super
是相对于this
的一个代码,它只在子类中发挥作用,可以通过super
来调用父类的属性。
- this:当前类的调用
- super:父类的调用
public class Person {
public String name = "Lao mi";
}
public class Student extends Person{
private String name = "小超";
//方法
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
public class Demo01 {
public static void main(String[] args) {
Person person = new Person();
Student student = new Student();
student.test("名字");
}
}
可以发现,当我们在子类中使用super.name
时,name返回了父类中name的值。而this.name
返回了在当期类,也就是子类中的值。
5.3 方法的重写
子类会基础父类的全部公开属性和方法,而其中的一些方法是我们不需要的,或者需要改变的,那么我们可以在子类中将该方法重写。
public class Person {
//方法
public void test(){
System.out.println("测试");
}
}
public class Student extends Person{
//方法
@Override
public void test(){
System.out.println("重写");
}
}
在注解@Override
后就是我们重写后的方法,方法名相同,但方法体不同,我们就可以实现,覆盖父类的方法,我们就能达成子类与父类要实现不同功能的要求。
- 重写的方法名必须相同。
- 参数列表必须相同。
- 修饰符的范围只能扩大。
- 抛出的异常范围只能缩小。
6. 多态
一个对象的实际类型是确定的,但它的引用类型可以是它的父类。
6.1 代码表现
public class Demo01 {
public static void main(String[] args) {
Student s = new Student();
Person s2 = new Student();
}
}
此时,对象s2是Student类的实例,但它的引用是指向Person类的,它只能调用Person类的方法,而对象s的引用是指向Student类的,它可以调用自身类的方法,也能调用从父类继承而来的方法。
这里是比较抽象的概率,为什么子类的实例可以指向父类呢?
我的理解是,在内存建立实例时,子类通过继承关系,可以将引用指向父类,来建立实例。
儿子去银行贷款,内存银行不给带,儿子就说了:“我爹是P大人,你敢不给我贷款?”
经理一听,“原来是P大人的儿子S公子啊。随便贷,随便贷。“
这个时候银行就以P父为登记,建立了S子的账户。
当账户有疑问的时候,银行也就找到登记时登记的P大人,而不是S公子。
当然这只是一个抽象的玩笑。
- 多态是方法的多态,和属性无关。
- 父类和子类有联系,才能利用多态的特性建立对象。
6.2 类型转换
当我们想通过子类为引用建立父类对象,或者父类想执行子类的方法时,都会出现报错,使我们无法达成。这时可以通过类型转换,将对象的引用指向子类,并且转换为子类的对象来实现。
public class Demo01 {
public static void main(String[] args) {
Student s1 = (Student) new Person();
Person s2 = new Student();
}
}
6.3 instanceof运算符
用于判断两个对象是否有父子关系,它的值是布尔值。
public static void main(String[] args) {
Student s1 = new Student();
Person s2 = new Student();
System.out.println(s1 instanceof Student);
System.out.println(s2 instanceof Student);
}
}
- X instanceof Y
- 当对象X是Y类或者它的子类的实例时,返回值为true。
- 当对象X不是Y类或者它的子类的实例时,返回值为flase。
7. 抽象类
通过abstract实现抽象类。
- 抽象类不能new来创建实例,只能通过子类去实现它:约束。
- 继承了抽象类的子类必须要实现它的方法。
- 抽象类可以有普通方法和抽象方法,抽象方法只能通过重写实现。
public abstract class Action {
public abstract void doSomething();//抽象方法
}
public class A extends Action{
@Override
public void doSomething() {
}
8. 接口
如果说类是具体的,那么抽象类既是具体,又是抽象的,而接口就是抽象的。
- 接口只有规范约束,没有普通的方法,只有抽象方法。
-声明关键字interface
8.1 代码表现
public interface UserService {
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface TimeService {
void time();
}
public class UserServiceImpl implements UserService,TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void time() {
}
}
8.2 特点
- 类实现接口 implements
- 实现了接口的类必须重写实现它所有的方法
- 一个类可以实现多个接口,接口可以多继承
9.内部类
在A类的内部再定义一个B类,B类对于A类来说是它的内部类。
9.1 代码实现
public class Outer {
private int id;
public void out(){
System.out.println("外部类");
}
class Inner{
public void in(){
System.out.println("内部类");
}
}
}
9.2 特性
我们不能通过main()方法直接调用内部类,但我们可以通过将内部类实例化,再用main()方法直接调用内部类。
public class Act {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
outer.out();
inner.in();
inner.getId();
}
}
一个Java文件中可以有多个class
,但只能有一个public class
。
甚至可以在方法中实现局部内部类。