1.初识面向对象
-
面向对象思想:物以类聚,分类的思维模式,首先对方法进行分类,然后对每个分类进行面向过程的思索。
-
面向对象编程(OOP)的本质:以类的方式组织代码,以对象的组织封装数据
-
三大特性:
- 封装
- 继承
- 多态
-
类:对具体事物的共同点的抽象,比如张三李四都是人,人便是一个类,Person类;
-
对象:具体的实例,比如张三就是人的一个具体实例,张三家里的狗旺财就是狗的一个具体实例
2.方法回顾和加深
- 见Day04
3.对象的创建分析
-
创建对象:new;例如:new 类名(); 类名 对象名 = new 类名();
- 使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
- 使用new关键字,本质是在调用构造器
-
例子:
//学生类 public class Student { // 属性:字段 String name; //null int age; //0 // 方法 public void study(){ System.out.println(this.name + "在学习"); } }
//一个项目应该只存在一个main方法 public class Application { public static void main(String[] args) { // 类:抽象的,需要实例化 // 类实例化后返回一个自己的对象 // student对象就是一个Student类的具体实例!即类会生小孩(对象) Student xiaoming = new Student(); Student xiaohong = new Student(); xiaoming.name = "小明"; xiaoming.age = 11; xiaohong.name = "小红"; System.out.println(xiaoming.name); //小明 System.out.println(xiaoming.age); //11 xiaoming.study(); //小明在学习 System.out.println(xiaohong.name); //小红 System.out.println(xiaohong.age); //0 } }
-
构造器
- 一个类即使什么都不写,也会存在一个方法,即无参构造器
-
必须和类的名字相同
-
必须没有返回类型,也不能写void
-
alt + insert 可自动生成构造器()
-
this.某某,指的是当前类的参数;=后面,指的是参数传进来的值
-
public class Person { String name; // 使用new关键字,本质是在调用构造器, // 无参构造器作用: /* 1.初始值对象的值 * */ public Person(){ name = "石佩"; } // 有参构造器;注意:一旦定义了有参构造,无参构造必须显示定义 public Person(String name){ this.name = name; } }
4.类与对象小结
1.类与对象
类是一个模板,抽象的;对象是一个具体的实例
2.类:
静态的属性--属性
动态的行为--方法
3.属性:字段Field 成员变量
定义格式:修饰符 属性类型 属性名 = 属性值;
默认初始化:
数字:0 0.0
char:u0000
boolean:false
引用:null
4.方法
定义,调用!
5.对象的引用
引用类型:对象 & 数组
对象是通过引用来操作的:栈--->堆(地址)
6.对象的创建和使用
定义格式: Person person = new Person;
必须使用new关键字创造对象,new的本质:调用构造器
对象的属性 person.name
对象的方法 person.sleep();
5.面向对象三大特性
-
封装
-
该露的露,该藏的藏。设计程序追求“高类聚,低耦合”
-
属性私有,get/set
-
作用:1.提高程序安全性,保护数据;2.隐藏代码的实现细节;3.统一接口;4.系统可能维护增加了
-
-
//类 private:私有 public class Student { //属性私有 private String name; private int age; private char sex; //属性私有了,其他类不能再通过Student实例化使用这些属性了 }
-
例子:
//类 private:私有 public class Student { //属性私有 private String name; private int age; private char sex; //属性私有了,其他类不能再通过Student实例化使用这些属性了 //故提供一些可以操作这些属性的方法 //提供一些public的get、set方法 //get:可以让其他类获得这个数据 public String getName() { return this.name; } //set:给这个数据设置值 public void setName(String name) { this.name = name; } }
public class Application { public static void main(String[] args) { Student sp = new Student(); sp.setName("石佩"); System.out.println(sp.getName()); // 打印结果 石佩 } }
-
alt – insert --Getter and Setter 可以自动生成get和set方法
-
继承
-
extend,类跟类之间的关系
-
特点:子类可以继承分类所有的public方法、属性
//Person 人:父类 public class Person { public void say(){ System.out.println("说了一句话"); } public void money(){ System.out.println("10亿"); } private void cerete(){ System.out.println("打牌"); } }
-
-
在java中所有的类都继承Object类
-
super
例子:
//Person 人:父类 public class Person { protected String name = "shipei"; }
//Student is 人 public class Student extends Person{ private String name = "penny"; public void test(String name){ System.out.println(name); //石佩 System.out.println(this.name); //penny System.out.println(super.name); //shipei } }
public class Application { public static void main(String[] args) { Student student = new Student(); student.test("石佩"); } }
-
-
super笔记
super注意点: 1.继承了父类的子类会默认调用一个super(); 如果父类写了一个有参的构造器,必须再显示的加一个无参的构造器,否则子类会报错。(见下图) 2.super调用父类的构造方法,必须处于子类构造方法的前面 3.super必须只能出现在子类的方法或构造方法中 4.super和this 不能同时调用构造方法(即super();和this();不可同时使用) super VS this: 1.代表的对象不同: this: 本类对象的引用 super:代表父类对象的引用 2.前提: this:没有继承也可以使用 super:只能在继承条件下才可以使用 3.构造方法: this(); 本类构造 super(); 父类构造
-
修正:
-
方法重写
-
静态方法不能重写
public class B { public static void test(){ System.out.println("B-->test()"); } }
public class A extends B{ public static void test(){ System.out.println("A-->test()"); } }
public class Application { public static void main(String[] args) { //静态方法的调用只和左边的定义的类型有关 // 与右边的new的对象无关 A a = new A(); a.test(); //A-->test() //父类的引用指向了子类 B b = new A(); b.test(); //B-->test() } }
-
非静态方法可以重写
override表示重写,下图带有字母O的蓝底色图形,为重载的标志
-
```java
public class B {
public void test(){
System.out.println("B-->test()");
}
}
```
```java
public class A extends B{
@Override //注解:有功能的注释,表示重写
public void test() {
System.out.println("A-->test()");
}
}
```
```java
public class Application {
public static void main(String[] args) {
A a = new A();
a.test(); //A-->test()
B b = new A(); //子类重写了父类的方法
b.test(); //A-->test()
}
}
```
- 重写小结:
```bash
重写注意点:
1.前提:
需要继承关系,子类重写父类的方法
方法名必须相同
参数列表必须相同
修饰符范围,子类的 >= 父类的;Public > Protected > Default > Private
抛出的异常范围,子类的 <= 父类的;ClassNotFoundException < Exception
2.使用:
Alt + Insert --> 点击override
3.非静态方法才可重写
重写与重载的区别:
1.定义区别:
①重载是指不同的函数使用相同的函数名,但是函数的参数个数或类型不同,
调用的时候根据函数的参数来区别不同的函数。
②重写(也叫覆盖)是指在派生类中重新对基类中的虚函数(注意是虚函数)重新实现,
即函数名和参数都一样,只是函数的实现体不一样。
2.类的关系区别:
重写是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。
3.产生方法区别:
重写只能由一个方法或只能由一对方法产生关系;重载是多个方法之间的关系。
4.参数列表要求区别
重写要求参数列表相同;重载要求参数列表不同。
5.调用方法区别
重写关系中,调用方法体是根据对象的类型来决定;
重载关系是根据调用时的实参表与形参表来选择方法体的。
```
-
多态
-
父类引用指向子类对象,这种特点,允许不同类的对象对同一方法作出响应
例如下面三句话,引用类型不同但指向同一个子类对象。
Student s1 = new Student(); Person s2 = new Student(); //父类的引用(父类对象)指向子类对象 Object s3 = new Student();
-
功能:实现动态编译,程序可扩展性增强
-
例子:
public class Person { public void run(){ System.out.println("run"); } }
public class Student extends Person{ @Override public void run() { System.out.println("son"); } public void eat(){ System.out.println("eat"); } }
public class Application { public static void main(String[] args) { //一个对象的实际类型是确定的 //new Student(); //new Person(); //但可以指向的引用类型就不确定了 Student s1 = new Student(); Person s2 = new Student(); //父类的引用指向子类对象 Object s3 = new Student(); s1.eat(); //eat s1.run(); //son s2.eat(); //报错 对象执行哪些方法,主要由对象左边的类型决定;Person父类型,可以指向子类,但不能调用子类自己写的方法 s2.run(); //son 子类重写了父类的方法,尽管s2为Person的引用但执行的是子类重写的方法 } }
-
多态小结
多态注意点: 1.多态是方法的多态,属性没有多态 2.父类和子类,有联系 类型转换异常(ClassCastException) 3.存在条件: 1)继承关系; 2)方法需要重写; 这些方法不可被重写: -static方法,属于类,它不属于实例 -final修饰的方法,处于常量池 -private修饰的方法 3)父类的引用指向子类对象 Father f1 = new Son();
-
instanceof和类型转换
-
instanceof:用于判断一个对象与另一个对象是否存在继承关系,这样就可以知道这个对象是什么类型;是则返回true,否则返回false
public class Person { public void run(){ System.out.println("run"); } }
public class Student extends Person{ public void walk(){ System.out.println("walk"); } }
public class Teacher extends Person{ }
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 Object); //true System.out.println(object instanceof Person); //true System.out.println(object instanceof Student); //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 Object); //true System.out.println(person instanceof Person); //true System.out.println(person instanceof Student); //true System.out.println(person instanceof Teacher); //false //System.out.println(person instanceof String); //编译报错,Person和String没有关系,他们之间不能进行比较和转化 System.out.println("==========="); Student student = new Student(); System.out.println(student instanceof Object); //true System.out.println(student instanceof Person); //true System.out.println(student instanceof Student); //true //System.out.println(student instanceof Teacher); //编译报错,Student和Teacher没有关系 //System.out.println(student instanceof String); //编译报错,Student和String没有关系 } }
-
类型转换:把父类转换为子类,由高向低转,强制转换;把子类转换为父类,由低向高转,直接转换
public class Application { public static void main(String[] args) { //类型之间的转换 父 子 Person person = new Student(); Student student = (Student) person; //高到低,强制转换 student.walk(); Student student1 = new Student(); Person person1 = student1; //低到高,直接转换
//子类中由walk方法,Person类中没有walk方法,Person类型的引用需要调用walk方法可将其类型强制转化为Student类型 变为:((Student) person).walk();
-
-
-
补充static
//static方法和属性的特点 public class Student { //属性 private static int age; //静态变量 多线程! private double score; //非静态变量 //方法 public static void go(){ } public void run(){ go(); }; public static void main(String[] args) { Student s1 = new Student(); //静态属性既可以用对象调用,也可以直接通过类名调用 System.out.println(Student.age); //System.out.println(Student.score); //编译报错 System.out.println(s1.age); System.out.println(s1.score); //静态方法既可以用对象调用,也可以用类名调用,也可以直接用; // 非静态方法可以直接使用静态方法 Student.go(); go(); s1.go(); s1.run(); //run(); //编译出错 } }
//静态代码块 public class Person { //2. { //代码块(匿名代码块),,可用于赋初值 System.out.println("匿名代码块"); } //1. 只执行一次 static{ //静态代码块 System.out.println("静态代码块"); } //3. public Person(){ System.out.println("构造方法"); } public static void main(String[] args) { new Person(); System.out.println("============"); new Person(); } }
//静态导入包
package com.oop.demo07;
//静态导入包
import static java.lang.Math.random;
/**
* @Author:Sp
* @Date:2021/1/21
* @Description:com.oop.demo07
*/
public class Test {
public static void main(String[] args) {
// 不导入静态包,应该写Math.random()
//导入静态包,可直接写random()
System.out.println(random());
}
}
6.抽象类和接口
-
抽象类:用abstract修饰的类
-
特点:
1. 抽象类不能new,即不能实例化,只能靠子类去实现它。抽象类中有构造方发
2. 抽象类中可以写普通方法
3. 抽象方法必须再抽象类中 -
类A继承类Action,必须要实现Action类中的抽象方法
-
```java
//abstract 抽象类
public abstract class Action {
//抽象方法:只有方法名字,没有方法实现!
public abstract void doSomething();
//特点:不能new,只能靠new子类去实现它
}
```
```java
//继承了抽象类的子类,必须要实现抽象类的方法,除非子类也是抽象类
public class A extends Action{
@Override
public void doSomething() {
}
}
```
-
接口:用interface修饰的类
-
特点:
1. 比抽象类(具体方法和抽象方法都有)还抽象,只有方法的声明,自己无法写方法
2. extends只能单继承,利用接口可以实现多个接口
3. 继承了接口的类必须重写接口中的方法
4. 接口不能不能被实例化,接口中没有构造方法 -
例子:
//interface定义接口 public interface UserService { //常量~public static final int AGE = 99; //接口中的所有定义的方法都是抽象的public abstract void add(String name); void delete(String name); void update(String name); void query(String name); }
public interface TimeService { }
//实现了接口的类,必须重写接口中的方法 //利用接口可实现多继承 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) { } }
-
7.内部类及OPP实战
-
内部类:一个类的内部定义了另一个类。比如,A类中定义了一个B类,那么B类相对于A类来说就称为内部类,A类相对于B类来说是外部类
-
成员内部类
- 可以获得外部类的私有属性
- 可以使用外部类的方法
//Outer为外部类 public class Outer { private int id; public void out(){ System.out.println("这是外部类的方法"); } public class Inner{ public void in(){ System.out.println("这是内部类的方法"); } public void getID(){ System.out.println(id); } public void fun(){ out(); } } }
public class Application { public static void main(String[] args) { // new Outer outer = new Outer(); outer.out(); // 这是外部类的方法 //通过外部类来实例化内部类 Outer.Inner inner = new Outer().new Inner(); //或 Outer.Inner inner1 = outer.new Inner(); inner.in(); // 这是内部类的方法 inner.getID(); // 0 inner.fun(); // 这是外部类的方法 } }
-
静态内部类
public class Outer { private static int id; public void out(){ System.out.println("这是外部类的方法"); } public static class Inner{ public void in(){ System.out.println("这是内部类的方法"); } public void getID() { System.out.println(id); } } }
-
局部内部类:在方法里面定义一个类
public class Outer { //局部内部类 public void method(){ class Inner{ //方法、属性 } } }
-
匿名内部类
public class Test { public static void main(String[] args) { //正常情况下 Apple apple = new Apple(); apple.eat(); //匿名内部类:没有名字而去初始化类, 不用将实例保存到变量中 new Apple().eat(); new UserService(){ @Override public void hello() { System.out.println("Hello World!"); } }.hello(); } } class Apple{ public void eat(){ System.out.println("Eat Apple."); } } interface UserService{ void hello(); }
-