面向对象
面向对象编程(Object-Oriented Programming, OOP)
面向对象编程的本质就是:以类的方式组织代码,以对象的形式封装数据。
三大特性:封装、继承、多态
对象的创建分析
类和对象的关系:
类是一种抽象的数据类型,它是对某一类食物整体描述/定义,但是并不能代表某一个具体的事物。
对象是抽象概念的具体实例。
package com.oop.demo01;
//学生类
public class Student {
//属性
String name;
int age;
//方法
public void study(){
System.out.println(this.name + "在学习");
}
}
package com.oop.demo01;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//类:抽象的,实例化
//类实例化后会返回一个自己的对象
//对Student类实例化产生对象
Student xiaoming = new Student();
Student xiaohong = new Student();
xiaoming.name = "小明";
xiaoming.age = 3;
System.out.println(xiaoming.name); //小明
System.out.println(xiaoming.age); //3
System.out.println(xiaohong.name); //null
System.out.println(xiaohong.age); //0
}
}
构造器:和类名相同;没有返回值
作用:new本质是在调用构造方法;初始化对象的值
注意:定义有参构造之后,如果想使用无参构造,需要显式定义一个无参的构造。
总结:
面向对象三大特性
封装
package com.oop.demo02;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("rain");
System.out.println(s1.getName());
s1.setAge(88);
System.out.println(s1.getAge());
}
}
package com.oop.demo02;
public class Student {
//属性私有
private String name;
private int id;
private char sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 120 || age <0){
this.age = 3;
}
this.age = age;
}
}
封装的作用:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护性增加
继承
package com.oop.demo03;
public class Person {
public int money = 10_0000_0000;
public void say(){
System.out.println("say hello");
}
//如果money是私有属性,可以通过这种方法来获取
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
package com.oop.demo03;
//子类继承了负累,就会拥有父类的全部方法
public class Student extends Person{
}
package com.oop.demo03;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
System.out.println(student.money);
}
}
super
super注意点:
- super 调用父类的构造方法,必须在构造方法的第一个
- super 必须只能出现在子类的方法或者构造方法中
- super 和 this不能同时调用构造方法(都需要在第一行)
VS this:
代表的对象不同:this:本身调用者这个对象 super: 代表父类对象的应用
前提:this:没有继承也可以使用 super:只能在继承条件才可以使用
构造方法:this():本类的构造 super():父类的构造
重写:需要有继承关系,子类重写父类的方法
4. 方法名必须相同
5. 参数列表必须相同
6. 修饰符:范围可以扩大 public > Protected > Default > private
7. 抛出的异常:范围可以被缩小,但不能扩大 ClassNotFoundException --> Exception
重写,子类的方法和父类必须要一致,方法体不同。
为什么要重写:父类的功能子类不一定需要,或者不一定满足(Alt+Insert override)
多态
多态:
- 多态是方法的多态,属性没有多态
- 父类和子类,有联系 父类调用子类独有的方法会强制转换. ClassCastException
- 存在的条件:继承关系,方法需要重写,父类引用指向子类对象(执行:看左边的类型,是谁就执行谁的方法,如果都有相同的方法就执行子类的)
不能重写的方法:
- static 静态方法,属于类,它不属于实例
- final 常量,无法改变
- private 私有方法无法重写
instanceof:判断关系
强制转换
高转低:
或:((Student) obj).go();
低转高:子类转换为父类,可能会丢失自己的一些方法。
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型;
- 把父类转换为子类,向下转型:强制转换
- 方便方法的调用,减少重复的代码,简洁
package com.oop.demo07;
public class Student {
private static int age; //静态的变量,多线程
private double score; //非静态的变量
public void run(){
go(); //非静态方法调用静态方法
}
public static void go(){
}
public static void main(String[] args) {
new Student().run(); //静态方法无法直接调用非静态方法
Student.go(); //静态方法调用静态方法
}
}
不是 static 修饰的方法,需要new对象去调用;static修饰的方法,可以直接调用,它在当前类中。
非静态方法可以去调用静态方法里的东西,静态方法可以调用静态方法,不能调用非静态方法。
匿名代码块和静态代码块:
package com.oop.demo07;
public class Person {
//2 赋初始值
{
System.out.println("匿名代码块");
}
//1:只执行一次~ 第二次不会再输出
static {
System.out.println("静态代码块");
}
//3
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("====================");
Person person2 = new Person(); //第二次执行不会再输出静态代码块
}
}
final修饰的类不能被继承,无子类。
抽象类和接口
抽象类
package com.oop.demo08;
//abstract 抽象类 类:extends Java类 单继承 (借口可以多继承)
public abstract class Action {
//约束,有人帮我们实现
//abstract,抽象方法,只有方法名字,没有
public abstract void doSomething();
}
package com.oop.demo08;
//抽象类的所有方法,继承了它的子类,都必须要实现它的方法,除非它也是抽象方法
public class A extends Action{
@Override
public void doSomething() {
}
}
抽象类的特点:
- 不能new这个抽象类,只能靠子类去实现它:约束
- 抽象类里可以写抽象方法
- 抽象方法必须在抽象类中
接口
接口:
- 约束
- 定义一些方法,不同的人来实现
- 方法都是 public abstract ,常量是 public static final
- 接口不能被实例化,接口中没有构造方法
- implements可以实现多个接口,必须要重写接口中的方法
内部类及OOP实战
内部类:
package com.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 void getID(){
System.out.println(id);
}
}
//静态内部类为 public static class Inner 静态内部类无法访问非静态属性
}
//一个java类中可以有多个class类,但只能有一个 public class
package com.oop.demo10;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.getID();
}
}
局部内部类:
package com.oop.demo10;
public class Local {
//局部内部类 放在方法里
public void method(){
class Inner{
}
}
}
匿名内部类:
package com.oop.demo10;
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();
}