面向对象 01:什么是面向对象
面向过程和面向对象
面向过程思想
步骤清晰简单,第一步做什么,第二步做什么。。。
面向过程适合处理一些较为简单的问题
Java
方法就是面向过程
面向对象思想
物以类聚,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对每个分类下的细节进行面向过程的思考。
面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
Java
类就是面向对象
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
面向对象编程
Object-Oriented Programming,简称OOP
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据。
三大特性:封装,继承,多态(不同的人用相同的方法,会得到不同的结果)
对象,是具体的事物。类,是抽象的,是对对象的抽象。
面向对象 04:类与对象的创建
类与对象的关系
类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物。
动物、植物、手机、电脑、Person类、Pet类、Car类等,这些类都是用来描述/定义某一类具体事物应该具备的特点和行为。
对象是抽象概念的具体实例
张三就是人的一个具体是实例,张三家里的旺财就是狗的一个具体实例。
能够体现出特点,展现出功能的是具体的实例,而不是一个抽象的概念。
创建与初始化对象
使用 new
关键字创建对象,会对创建好的对象分配内存空间、进行默认的初始化、对类中构造器的调用。
package opp.ClassObject;
public class App {
public static void main(String[] args) {
// 类实例化后会返回一个自己的对象!
// xiaoming、xiaohong 就是一个 Student 类的具体实例!
Student xiaoming = new Student();
Student xiaohong = new Student();
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
xiaoming.study();
xiaohong.name = "小红";
xiaohong.age = 18;
System.out.println(xiaohong.name);
System.out.println(xiaohong.age);
xiaohong.study();
}
}
package opp.ClassObject;
public class Student {
// 属性
String name;
int age;
public void study(){
System.out.println(this.name + "在学习");
}
}
面向对象 05:构造器详解
package opp.Constructor;
public class App {
public static void main(String[] args) {
Person person = new Person("lb", 23);
System.out.println(person.name);
System.out.println(person.age);
}
}
package opp.Constructor;
public class Person {
String name;
int age;
/*
构造器:
1. 构造器名必须与类名相同;
2. 没有返回值
快捷键:
按 Alt + Insert 快速生成构造函数
*/
// 一个类即使什么都不写,它也会存在一个无参构造方法
// 无参构造的显式定义如下,默认如此,可不写
public Person() {
}
// 有参构造,写了有参构造,默认的无参构造会失效,要调用无参构造,必须手动写上无参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
面向对象 06:创建对象内存分析
package opp.NewAnalysis;
public class App {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
System.out.println(dog.name);
System.out.println(dog.age);
dog.shout();
Pet cat = new Pet();
}
}
package opp.NewAnalysis;
public class Pet {
String name;
int age;
public void shout(){
System.out.println(this.name + "叫了一声");
}
}
面向对象08:封装详解
封装
该露的露,该藏的藏
程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是仅暴露少量的方法给外部使用。
封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
优点
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 增强系统可维护性
package opp.PackageAnalysis;
public class App {
public static void main(String[] args) {
Student s1 = new Student();
Student s2 = new Student();
s1.setId(1);
s1.setName("lb");
s1.setGender('男');
s1.setAge(18);
s2.setAge(101);
System.out.println(s1.getId());
System.out.println(s1.getName());
System.out.println(s1.getGender());
System.out.println(s1.getAge());
System.out.println(s2.getAge());
}
}
package opp.PackageAnalysis;
public class Student {
// 属性私有
private String name; // 名字
private int id; // 学号
private int age; // 年龄
private char gender; // 性别
// 提供一些可以操作这些属性的public的get和set方法
// get 获得数据
public String getName(){
return this.name;
}
// set 给属性设置值
public void setName(String name){
this.name = name;
}
// 可按alt + insert后,点Getter和Setter快速生成
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public char getGender() {
return gender;
}
public void setGender(char gender) {
this.gender = gender;
}
public int getAge() {
if(age == 0){
return -1; // 年龄输入错误,返回 -1
}else{
return age;
}
}
public void setAge(int age) {
if(age > 0 && age < 100){
this.age = age;
}
}
}
面向对象 09:什么是继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字 extends
(“扩展”)来表示。
Java
中类只有单继承,没有多继承。即一个子类只能有一个父类,但一个父类可以有多个子类。
类与类之间的关系除了继承之外,还有依赖、组合、聚合等。
package opp.person;
public class Application {
public static void main(String[] args) {
Student student = new Student();
System.out.println(student.getMoney());
student.say();
}
}
package opp.person;
// 父类
// Ctrl + H 打开继承树
// 在 Java 中,所有的类都直接或间接继承 Object 类
public class Person {
private int money = 100;
public void say(){
System.out.println("说了一句话");
}
public int getMoney() {
return money;
}
}
package opp.person;
// 子类继承了父类,就会拥有父类的全部非 private 属性和非 private 方法
public class Student extends Person{
}
package opp.person;
public class Teacher extends Person{
}
面向对象 10:Super详解
package opp.Super;
public class Application {
public static void main(String[] args){
Student student = new Student();
System.out.println("=======testVariable========");
student.testVariable("lb");
System.out.println("=======testFunction========");
student.testFunction();
}
}
package opp.Super;
public class Student extends Person{
public Student(){
// 首行隐藏了代码 super(); 调用了父类的无参构造
super(); // 该语句必须在子类无参构造器的第一行
//this(); // super() 和 this() 不能同时调用构造方法,都只能在第一行
System.out.println("Student无参构造执行了");
}
private String name = "qinjiang";
public void print(){
System.out.println("Student");
}
public void testVariable(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void testFunction(){
print();
this.print();
super.print();
}
}
package opp.Super;
public class Person {
public Person(){
System.out.println("Person无参构造执行了");
}
protected String name = "kuangshen";
public void print(){
System.out.println("Person");
}
}
面向对象 11:方法重写
package opp.MethodOverride.HaveStatic;
// 子类和父类的方法有 static
public class App {
public static void main(String[] args){
// 有 static,方法的调用只和左边定义的数据类型有关
A a = new A();
a.test();
// A a1 = new B(); // 会报错
// a1.test();
// 父类的引用指向了子类
B b = new A();
b.test();
B b1 = new B();
b1.test();
}
}
package opp.MethodOverride.HaveStatic;
public class A extends B{
public static void test(){
System.out.println("A->test");
}
}
package opp.MethodOverride.HaveStatic;
public class B {
public static void test(){
System.out.println("B->test");
}
}
package opp.MethodOverride.NoStatic;
// 子类和父类的方法无 static
public class App {
public static void main(String[] args){
// 无 static,方法的调用只和右边 new 的有关
A a = new A();
a.test();
// A a1 = new B(); // 会报错
// a1.test();
// 父类的引用指向了子类
B b = new A();
b.test();
B b1 = new B();
b1.test();
}
}
package opp.MethodOverride.NoStatic;
public class A extends B {
// ctrl + o 重写方法
@Override // 注解:有功能的注释
public void test() {
System.out.println("A->test");
}
}
package opp.MethodOverride.NoStatic;
public class B {
public void test(){
System.out.println("B->test");
}
}
重写
需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符范围可以扩大但不能缩小: public > protected > default > private
- 抛出异常的范围可以缩小但不能扩大
为什么需要重写?
父类的功能子类不一定需要;父类的功能不够完善,不能满足子类的需要。
面向对象 12:什么是多态
package opp.polymorphism;
public class App {
public static void main(String[] args){
// 一个对象的实际类型是确定的
// new Student();
// new Person();
// 可以指向的引用类型就不确定了:父类的引用指向子类
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
s2.run(); // 子类重写了父类的方法,执行子类的方法
// s2.eat(); // 会报错。父类型可以指向子类,但是不能调用子类独有的方法
s1.eat();
}
}
package opp.polymorphism;
public class Person {
public void run(){
System.out.println("run");
}
}
package opp.polymorphism;
public class Student extends Person{
public void run(){
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
多态
即同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多。
多态注意事项
父类和子类必须有联系,不然会出现类型转换异常(ClassCastException)。
多态的存在条件
- 需要有继承关系
- 方法需要被重写
- 父类引用指向子类对象
方法的修饰符是以下三种的无法被重写:
-
static 属于类,不属于实例
-
final 常量
-
private
面向对象 13:instanceof 和类型转换
package opp.type;
public class App {
public static void main(String[] args) {
Object object = new Student();
// Object > Person > Student
System.out.println(object instanceof Student);
System.out.println(object instanceof Person);
System.out.println(object instanceof Object);
// Object > Person > Teacher 没 new Teacher(); 所以为false
System.out.println(object instanceof Teacher);
// Object > String
System.out.println(object instanceof String);
System.out.println("================================");
Person person = new Student();
// Person > Student
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
// Person > Teacher 没 new Teacher(); 所以为false
System.out.println(person instanceof Teacher);
//System.out.println(person instanceof String); // 不存在继承关系,编译报错
System.out.println("================================");
Student student = new Student();
System.out.println(student instanceof Student);
System.out.println(student instanceof Person);
System.out.println(student instanceof Object);
//System.out.println(student instanceof Teacher); // 不存在继承关系,编译报错
//System.out.println(student instanceof String); // 不存在继承关系,编译报错
student.go();
// 父类的引用可以指向子类的对象,反之不成立
Person person1 = student;
((Student)person).go(); // 父类转换为子类,需要进行强制转换
}
}
package opp.type;
public class Person {
public void run(){
System.out.println("run");
}
}
package opp.type;
public class Student extends Person{
public void go(){
System.out.println("go");
}
}
package opp.type;
public class Teacher extends Person{
}
面向对象14:static关键字详解
package opp.StaticAnalysis;
public class Student {
private static int age; // 静态的变量
private double score; // 非静态的变量
public void run(){
System.out.println("run() 调用 go()");
go(); // go() 是 static 的,先加载,可以被调用
}
public static void go(){
System.out.println("go");
}
public static void main(String[] args){
Student s1 = new Student();
System.out.println(Student.age);
//System.out.println(Student.score); // 会报错,score必须为static
System.out.println(s1.age);
System.out.println(s1.score);
go();
s1.go();
// run(); // 无法直接调用
s1.run();
new Student().run();
}
}
package opp.StaticAnalysis;
public class Person {
// 加载顺序:静态代码块 > 匿名代码块 > 构造器
// 可以用来赋初值
{
System.out.println("匿名代码块");
}
// 只执行一次
static{
System.out.println("静态代码块");
}
public Person(){
System.out.println("构造器");
}
public static void main(String[] args) {
Person person = new Person();
System.out.println("======================");
Person person1 = new Person();
}
}
package opp.staticps;
// 静态导入别的类的方法
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
System.out.println(random());
System.out.println(PI);
}
}
面向对象15:抽象类
package opp.abstractclass;
public class Application {
public static void main(String[] args) {
//Action action = new Action(); // 不能new这个抽象类(抽象类无对象),只能靠子类去实现它
}
}
package opp.abstractclass;
public abstract class Action {
String name;
int age;
// 抽象类存在构造器
public Action(){
System.out.println("存在构造器");
}
public Action(String name, int age) {
this.name = name;
this.age = age;
}
// 抽象方法,只有方法名,没有方法体
public abstract void doSomething();
/*
抽象类:
1. 不能new这个抽象类(抽象类无对象),只能靠子类去实现它
2. 抽象类中可以写普通的方法,而抽象方法必须在抽象类中
好处:相当于一个模板
*/
}
package opp.abstractclass;
public class A extends Action{
@Override
public void doSomething() {
}
}
面向对象16:接口的定义与实现
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有!
接口:只有规范,自己无法写方法,专业的约束!约束和实现分离:面向接口编程
接口就是规范,定义的是一组规则体现了现实世界中“如果你是…则必须能…”的思想。例:如果你是天使,则必须能飞。
接口的本质是契约,就像法律一样,制定好后大家都遵守。
面向对象的精髓,是对对象的抽象,最能体现这一点的就是接口。
package opp.Interface;
public interface UserService {
// 接口中所有定义的属性默认都是 public static final
public static final int age = 99;
// // 接口中所有定义的方法默认都是 public abstract
// // 接口不能被实例化,也就没有构造方法
// public abstract void run(){
//
// }
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
package opp.Interface;
// 类可以实现接口
// 实现接口的类,必须要重写接口的方法
// 利用接口可以实现多继承
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() {
}
}
package opp.Interface;
public interface TimeService {
void timer();
}
面向对象 17:N 种内部类
内部类就是在一个类的内部再定义一个类,比如,A 类中定义了一个 B 类,那么 B 类相对 A 类来说就称为内部类,而 A 类相对 B 类来说就是外部类了。
package opp.InnerClass;
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
// 局部内部类
public void method(){
class Local{ // 不能加 public 修饰符
}
}
public class Inner{ // 加上 static 修饰符,变成静态内部类,此时不能获得外部类的私有属性
public void in(){
System.out.println("这是内部类的方法");
}
// 获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
// 一个 .java文件 中可以有多个 class ,但是只能有一个 public class
class A{
}
package opp.InnerClass;
public class App {
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
outer.out();
inner.in();
inner.getID();
}
}
package opp.InnerClass;
public class Test {
public static void main(String[] args) {
// 匿名内部类,没有将实例赋给变量
new Apple().eat();
UserService userService = new UserService() {
@Override
public void Hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("1");
}
}
interface UserService{
void Hello();
}