面向过程&面向对象
面向过程:
- 步骤清晰简单,第一步做什么,第二步做什么......
- 面向过程适合处理一些较为简单的事情
面向对象:
- 物以类聚,分类的思维模式。思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
- 面向对象适合处理复杂的问题,适合处理需要多人协作的问题。
概述:对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
什么是面向对象?
面向对象(Object-Oriented Programming, OOP)的本质是以类的方式组织代码,以对象的方式封装数据。
三大特性:
- 封装
- 继承
- 多态
注意:
- 从认识论的角度考虑,是先有对象后有类。因为对象是具体的,而类是抽象的。类是对对象的抽象。
- 从代码运行的角度考虑,是先有类后有对象。类是对象的模板。
类与对象的关系
类是一种抽象的数据类型。它是对某一类事物的整体描述或定义,但并不能代表某一个具体的事物。
- 如:人、动物、植物、电脑、手机,等等......
对象是抽象概念的具体实例。
- 如:张三、隔壁家的小花猫咪咪、《唐伯虎点秋香》里的那只名叫旺财的狗
初始化与创建对象
创建的方式:使用new关键字创建对象
使用new关键字创建对象的时候,除了分配内存空间之外,还会给创建好的对象赋默认值进行初始化,以及调用类中的构造器。
示例:
Student类
package com.wmwx.oop.Demo01; //学生类 public class Student { //属性:字段 String name; int age; //方法 public void study(){ System.out.println("学生"+this.name+"在学习。"); } }
Application类(启动类)
package com.wmwx.oop.Demo01; //启动类 public class Application { //一个项目应该只存在一个main方法 public static void main(String[] args) { //类是抽象的,需要实例化 //类实例化后会返回一个自己的对象 //student对象是Student类的一个实例 Student student = new Student(); student.study(); //输出"学生null在学习。" student.name = "小明"; student.study(); //输出"学生小明在学习。" } }
构造方法
当一个对象被创建时候,构造方法用来初始化该对象。构造方法和它所在类的名字相同,但构造方法没有返回值。
一个类即使什么都不写,也会存在一个构造方法。因为 Java 自动提供了一个默认构造方法,其访问修饰符和类的访问修饰符相同。
一旦自己定义了构造方法,默认的构造方法就会失效。
示例:
Person类:
package com.wmwx.oop.Demo01; public class Person { String name; //使用快捷键alt+insert可以自动生成构造方法 //无参构造 public Person(){ this.name = "一个无名氏"; } //有参构造(一旦定义有参构造,就必须显式定义无参构造) public Person(String name){ this.name = name; } }
Application类:
package com.wmwx.oop.Demo01; public class Application { public static void main(String[] args) { //使用new关键字,本质是在调用构造方法 Person person1 = new Person(); //调用无参构造 System.out.println(person1.name); //输出"一个无名氏" //利用构造方法,可以初始化对象 Person person2 = new Person("惟妙惟霄"); //调用有参构造 System.out.println(person2.name); //输出"惟妙惟霄" } }
内存分析
过程如下:
- 创建类
- 在堆中存放类和类中的静态方法
- 创建对象
- 在堆中为对象开辟空间
- 在栈中存放对象的引用变量名
- 令对象的引用变量名指向堆中开辟的空间
封装
所谓封装,即该露的露,该藏的藏。程序设计要追求“高内聚,低耦合”。
高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
低耦合:仅暴露少量的方法给外部使用。
对于代码而言,总结起来就一句话:属性私有,get/set。
意义:
- 提升程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 提高了系统的可维护性
示例:
Student类:
package com.wmwx.oop.Demo03; public class Student { //属性私有 private String name; private int id; private String gender; private int age; //需要提供共有的get和set方法 //get方法:获取数据 public String getName() { return name; } //set方法:设置数据 public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public int getAge() { return age; } public void setAge(int age) { if (age<0||age>120){ this.age = 3; }else{ this.age = age; } } }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo03.Student; //启动类 public class Application { public static void main(String[] args) { Student student = new Student(); student.setName("惟妙惟霄"); student.setId(123456); student.setGender("男"); student.setAge(130); System.out.println(student.getAge()); //输出3 } }
继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
在 Java 中通过 extends 关键字可以声明一个类是从另外一个类继承而来的,其语法如下:
class 子类 extends 父类 { }
extends的意思是扩展,子类是对父类的扩展。
继承的注意事项:
Java只有单继承,没有多继承。
在Java中,所有类都默认直接或间接继承自Object类。
在Java中,可以使用this指代当前类,并使用super指代父类。
super的注意事项:
- super调用父类的构造方法,必须在构造方法的第一行。
- super只能出现在子类的方法或构造方法中。
- super和this不能同时调用构造方法。
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说,子类能够根据需要实现父类的方法。重写需要遵守以下规则:
- 方法名必须相同
- 参数列表必须相同
- 修饰符的范围可以扩大,但不能缩小
- 抛出的异常可以被缩小,但不能扩大
示例:
Person类:
package com.wmwx.oop.Demo04; //父类:人类 public class Person { private int money = 10_0000_0000; protected String name = "惟妙惟霄"; public Person() { System.out.println("Person的无参构造方法执行了!"); } public void say(){ System.out.println("说了一句话。"); } public int getMoney() { return money; } public void setMoney(int money) { this.money = money; } public void print(){ System.out.println("Person"); } }
Student类:
package com.wmwx.oop.Demo04; //子类:学生类 public class Student extends Person{ private String name = "妙霄"; public Student() { //隐藏代码:super(); //父类的构造方法必须要在子类的构造方法的第一行 System.out.println("Student的无参构造方法执行了!"); } public void test1(String name){ System.out.println(name); //输出参数 System.out.println(this.name); //输出当前类的name System.out.println(super.name); //输出父类的name } //重写都是方法的重写,与属性无关 //只允许重写public方法 //可以使用快捷键alt+insert来插入重写方法 @Override public void print() { System.out.println("Student"); } public void test2(){ print(); this.print(); super.print(); } }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo04.Person; import com.wmwx.oop.Demo04.Student; //启动类 public class Application { public static void main(String[] args) { Student student = new Student(); //第一行输出"Person的无参构造方法执行了!" //第二行输出"Student的无参构造方法执行了!" student.say(); //子类继承父类,就会拥有父类的public方法 System.out.println(student.getMoney()); //可以用父类的get/set方法对属性进行操作 //可以使用快捷键ctrl+H来查看继承树 student.test1("MiaoXiao"); //第一行输出"MiaoXiao" //第二行输出"妙霄" //第三行输出"惟妙惟霄" student.test2(); //第一行输出"Student" //第二行输出"Student" //第三行输出"Person" Student stu1 = new Student(); stu1.print(); //输出"Student" //父类的引用指向了子类 Person stu2 = new Student(); stu2.print(); //输出"Student" } }
多态
多态是同一个行为具有多个不同表现形式或形态的能力。当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。
多态存在的三个必要条件:
- 继承
- 重写
- 父类引用指向子类对象:Parent p = new Child();
不能被重写的方法:
- static 方法
- final 方法
- private 方法
示例:
Person类:
package com.wmwx.oop.Demo05; public class Person { public void run(){ System.out.println("人在跑步。"); } }
Student类:
package com.wmwx.oop.Demo05; public class Student extends Person{ @Override public void run() { System.out.println("学生在跑步。"); } public void eat(){ System.out.println("学生在吃东西。"); } }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo05.Person; import com.wmwx.oop.Demo05.Student; //启动类 public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的 //但可以指向的引用类型是不确定的 Student s1 = new Student(); Person s2 = new Student(); //父类的引用指向子类 Object s3 = new Student(); s1.run(); //输出"学生在跑步" s2.run(); //子类重写父类方法,将执行子类方法,输出"学生在跑步。" s1.eat(); //输出"学生在吃东西" //s2.eat(); //不能调用。对象能使用哪些方法,要看左边的类型。 ((Student)s2).eat(); //强制类型转换。输出"学生在吃东西。" } }
instanceof
Java中的instanceof关键字可以用来判断某一个对象是不是某一个类是实例。如果是,返回true;如果不是,返回false;如果二者无关,则编译不通过。
示例:
package com.wmwx.oop; import com.wmwx.oop.Demo06.Person; import com.wmwx.oop.Demo06.Student; import com.wmwx.oop.Demo06.Teacher; //启动类 public class Application { public static void main(String[] args) { //继承关系如下: //Object -> Person -> Student //Object -> Person -> Teacher //Object -> String Object object = new Student(); System.out.println(object instanceof Student); //输出true System.out.println(object instanceof Person); //输出true System.out.println(object instanceof Object); //输出true System.out.println(object instanceof Teacher); //输出false System.out.println(object instanceof String); //输出false System.out.println("====="); Person person = new Student(); System.out.println(person instanceof Student); //输出true System.out.println(person instanceof Person); //输出true System.out.println(person instanceof Object); //输出true System.out.println(person instanceof Teacher); //输出false //System.out.println(person instanceof String); //编译时报错 System.out.println("====="); Student student = new Student(); System.out.println(student instanceof Student); //输出true System.out.println(student instanceof Person); //输出true System.out.println(student instanceof Object); //输出true //System.out.println(student instanceof Teacher);//编译时报错 //System.out.println(student instanceof String); //编译时报错 } }
类型转换
- 子类转换为父类,是向上转型,可自动转换。
- 父类转换为子类,是向下转型,需强制转换。
示例:
Person类:
package com.wmwx.oop.Demo06; public class Person { public void run(){ System.out.println("人在跑步。"); } }
Student类:
package com.wmwx.oop.Demo06; public class Student extends Person{ public void walk(){ System.out.println("学生在走路。"); } }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo06.Person; import com.wmwx.oop.Demo06.Student; //启动类 public class Application { public static void main(String[] args) { //高 ----------------- 低 Person person = new Student(); ((Student)person).walk(); //强制类型转换 Student student = new Student(); Person obj = student; //子类转换为父类,可能会丢失一些方法 //obj.walk(); //编译时报错 } }
静态代码块
静态代码块会在类加载时执行,且只会执行一次。
示例:
Person类:
package com.wmwx.oop.Demo07; public class Person { //第二个执行,可在这里赋初始值 { System.out.println("匿名代码块"); } //第一个执行,只执行一次 static { System.out.println("静态代码块"); } //第三个执行 public Person() { System.out.println("构造方法"); } }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo07.Person; //启动类 public class Application { public static void main(String[] args) { Person person = new Person(); //第一行输出"静态代码块" //第二行输出"匿名代码块" //第三行输出"构造方法" } }
抽象类
在Java语言中使用abstract 来定义抽象类,其基本语法如下:
abstract class 类名{ //属性 //方法 }
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。在Java中一个类只能继承一个抽象类,但一个类可以实现多个接口。
在Java语言中使用abstract 来定义抽象方法,其基本语法如下:
abstract 访问修饰符 返回值类型 方法名(参数);
抽象类与抽象方法的规则:
- 抽象类不能被实例化(即不能被 new ),只有抽象类的非抽象子类可以创建对象。
- 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
- 抽象类中的抽象方法只是声明,不包含方法体,也就是不给出方法的具体实现。
- 构造方法、类方法(用 static 修饰的方法)不能声明为抽象方法。
- 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
示例:
Action类:
package com.wmwx.oop.Demo08; //使用abstract声明抽象类 public abstract class Action { //抽象方法,只有方法名,没有方法体 //仅作约束,期待他人实现 public abstract void doSomething(); }
A类:
package com.wmwx.oop.Demo08; public class A extends Action{ //子类必须实现父类的抽象方法 //除非该子类是抽象类 @Override public void doSomething() { } }
接口
接口在JAVA编程语言中是一个抽象类型,是抽象方法的集合,通常以 interface 来声明。其基本语法如下:
[访问修饰符] interface 接口名称 [extends 其他的接口名称] { // 抽象方法 }
接口的特性:
- 接口中每一个方法都是隐式抽象的,接口中的方法会被隐式地指定为 public abstract,并且只能是 public abstract。
- 接口中可以含有变量,但是接口中的变量会被隐式地指定为 public static final ,并且只能是 public static final。
- 接口中的方法不能在接口中实现,只能由实现接口的类来实现接口中的方法。
- 一个接口能继承另一个接口,使用 extends 关键字.子接口会继承父接口的方法。
当类实现接口的时候,需要实现接口中所有的方法。否则,类必须声明为抽象的类。Java中使用 implements 关键字实现接口,其基本语法如下:
class 类名 implements 方法名{ //实现接口中的抽象方法 }
示例:
UserService接口:
package com.wmwx.oop.Demo09; //定义接口使用关键字interface public interface UserService { //接口中的所有属性都是public static final //一般不在接口中定义属性 int age = 60; //接口中的所有方法都是public abstract void add(String name); void delete(String name); void update(String name); void query(String name); }
TimeService接口:
package com.wmwx.oop.Demo09; public interface TimeService { void timer(); }
UserServiceImpl类:
package com.wmwx.oop.Demo09; //类使用关键字implements来实现接口 //实现了接口的类,需要重写接口的所有方法 //一个类可以实现多个接口 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 timer() { } }
内部类
所谓内部类,就是在一个类的内部再定义一个类。
示例:
Outer类:
package com.wmwx.oop.Demo10; //外部类 public class Outer { private int id=10; public void out(){ System.out.println("这是外部类的方法!"); } public class Inner{ public void in(){ System.out.println("这是内部类的方法!"); } //获得外部类的私有属性 public int getId(){ return id; } } public void method(){ //局部内部类,在外部类的方法之中 class Inner{ } } } //一个java文件可以有多个class,但是只能有一个public class class A{ }
Application类:
package com.wmwx.oop; import com.wmwx.oop.Demo09.UserService; import com.wmwx.oop.Demo10.Outer; //启动类 public class Application { public static void main(String[] args) { //外部类使用new关键字 Outer outer = new Outer(); outer.out(); //内部类通过外部类来实例化 Outer.Inner inner = outer.new Inner(); inner.in(); System.out.println(inner.getId()); //匿名类,不用将实例保存到变量中 new Outer().out(); //使用匿名类实现接口 UserService userService = new UserService() { @Override public void add(String name) { } @Override public void delete(String name) { } @Override public void update(String name) { } @Override public void query(String name) { } } } }