学习009---面向对象oop

oop

以类的方式组织代码,以对象的组织(封装)数据

注:本系列学习自狂神说(Java):

点击跳转至狂神说视频(bilbili)

点击跳转至狂神说网页

当前的目标是建造自己的网页!

俺的博客:startsmaple

目录


面向过程

image

回顾

image

方法的定义

修饰符 返回值类型 方法名(参数){
    方法体;
    return 返回值;
}

方法的调用

//实例化这个类 new
//对象类型 对象名 = 对象值;
Student student = new Student();
student.say();

class Person{
    String name;
}

引用传递本质还是值传递

package com.oop.demo01;

public class Demo05 {
    //值传递
    public static void main(String[] args) {
        int a = 1;
        System.out.println(a);//1
        Demo05.change(a);
        System.out.println(a);//1
    }
    public  static void change(int a){
        a = 10;
    }
}


out:
    1
    1
package com.oop.demo01;

public class Demo06 {
    //引用传递
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.name);


        Demo06.change(person);
        System.out.println(person.name);
        //此处的person是一个对象,指向的是类里面的name

    }
    public static void change(Person person){
        person.name = "??????????????????????";
    }
}


class Person{
    String name;

}


out:
	null
    ???????????????????????

解析

本质是创建了一个引用对象person,person指向的还是Person person = new Person();

是一个具体的人,可以改变里面属性

构造器

语法

先创建一个类

package com.oop.demo02;

public class Person {
}

打开class文件,发现一个类如果什么都不写。class文件会自动生成一个方法
idea打开class文件

package com.oop.demo02;

public class Person {
    public Person() {
    }
}

此处的Person(){}即构造器(构造方法)

特点:

	- 必须和类名返回值相同
	- 必须没有返回类型,也不能写void
package com.oop.demo02;

public class Person {
	//属性
    String name;
    
    //作用是用来实例化、初始化值
    //1. 使用new关键字,本质是在调用构造器
    //Person person = new Person();
    //无参构造
    public Person(){
        this.name = "abc";
    }
    //2.有参构造,无参构造就必须显示定义
    //也就是说,如果你什么都不写,系统自动生成无参构造
    //但是你写了有参构造,系统就不帮你写了,你要自己写
    public Person(String name) {
        this.name = name;
    }
    //3.快捷键alt + insert 生成构造器


}
package com.oop.demo02;

//学生类
public class Student {
    //属性
    String name;
    //初始化默认0 0.0 
    //char   u0000
    //boolen 0(false)
    //引用	null
    
    int age;

    //方法
    public void study(){
        System.out.println("学生在学习");
    }
}
package com.oop.demo02;


//规范:一个项目应该只存在一个main
public class Application {
    public static void main(String[] args) {
        //类:是抽象的,实例化
        Person person = new Person();
        Person person2 = new Person("starsmaple");
        
        Student student = new Student();
        student.study();
    }
}

图解构造

image

image

方法区是特殊的堆

用idea打开class文件

打开项目结构
image
image

添加out目录,在out目录下寻找对应文件即可

三大特性

1. 封装

理解

即:该露的露,该藏的藏

  1. 高内聚,低耦合

    • 高内聚:类的内部数据操作自己完成,不允许外部干涉
    • 低耦合:只暴露少量的方法给外部使用
  2. 封装即隐藏

  3. 属性私有,get/set【只要记住这句话】

模板

package com.oop.demo04;

public class Student {

    //属性私有
    private String name;
    private int id;
    private char sex;
    private int age;

    //提供一些public来操作属性
    //get   set
    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }

    //快捷键 alt + insert


    //get set的作用
    //规避不合法
    //1.提高程序安全性,保护数据
    //2.隐藏代码细节
    //3.统一接口
    //4.系统可维护性增加了
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if(age>=0&&age<=120)
            this.age = age;
        else {
            System.out.println("The age if illegal");
            this.age = -1;
        }
    }
}
package com.oop.demo04;


public class Application {
    public static void main(String[] args) {
//Demo01
//        Student xiaoming = new Student();
//        Student xiaohong = new Student();
//
//        xiaohong.name = "小明";
//        xiaoming.age = 3;
//
//        System.out.println(xiaohong.name);
//        System.out.println(xiaohong.age);
//
//
//		
//
// Demo02
        System.out.println("Demo02======================");
        Student student01 = new Student();
        student01.setAge(999);
        System.out.println(student01.getAge());;

    }
}

get set的作用

​ //规避不合法
//1.提高程序安全性,保护数据
//2.隐藏代码细节
//3.统一接口
//4.系统可维护性增加了

2. 继承

本质是对类再次抽象

extends拓展,子类是父类的拓展

java中只有单继承

引入

继承

先创建

package com.oop.demo05;

//父类,基类

public class Person {
    protected String name  = "Father:Person";
    public int money = 10_0000_0000;
    public Person() {
        System.out.println("Person无参构造");
    }
    public test(String str){
        System.out.println(str);
    }
}
package com.oop.demo05;
//子类(派生类,
public class Student extends Person{
}
package com.oop.demo05;

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.test("main");//使用父亲的方法
        student.money -= 10000;//儿子花掉了父亲的钱
}

创建了子类,却能使用父类的test,即继承

组合
package com.oop.demo05;

//组合
public class Teather {
    Person person;
}

等级

public > protected > default > private

如果父类属性私有,则子类无法访问

一般来说属性都为私有,而留有接口get()set()来让人修改

Object类

每个类都会直接或间接继承object类

package com.oop.demo05;

public class Person extends Object{
}

其中extends Object 没有必要写

super()

每个子类都会在第一行出现super();调用父类的无参构造(隐藏代码,默认自动添加

所以如果父类没有无参构造,子类要自己写super有参构造

如果super(); 上面有东西 会报错

******同样的,this();构造器也要放在第一行

package com.oop.demo05;
//子类(派生类,
public class Student extends Person{
    super();//可写可不写
    //继承时,自动会在最上方添加super();
    //相当于构建了一个父类
    //父类必须要有无参构造,否则只能调用父类的有参
    private String naem  = "Student";

    //在此处就不能写super();必须写在子类第一行
    public void test(String name){
        System.out.println(name);
        System.out.println(this.naem);
        System.out.println(super.name);//访问父类的属性(public)
    }
    public Student() {
        System.out.println("Student 无参构造");
    }
}
注意点:
super注意点:
1.super调用父类的构造方法,必须在构造方法的最上面(第一个
2.super只能出现在子类或构造方法中
3.super和this不能同时调用构造方法


super Vs this
1.代表对象不同
2.前提:
    this没有继承也能用
3.构造方法:
    this调用本类的构造
    super调用父类的构造

重写

子类重写父类的方法

不能重写的:
static
final 常量
private

重写只能是public

package com.oop.demo05;

public class A extends B {
    
    @Override//注解,有功能的注解!!
    public void test() {
        System.out.println("A=>test()");
    }
}
package com.oop.demo05;

//重写都是方法的重写和属性无关
public class B {
    
    public void test(){
        System.out.println("B=>test()");
    }
}
package com.oop.demo05;

public class Application {
    public static void main(String[] args) {

        //方法的调用只和左边,定义的数据类型有关
        A a = new A();
        a.test();
        
        //父类的引用指向了子类
        B b = new A();//子类重写父类的方法
        //重写只能是public
        b.test();
    }
}

//out
//A=>test()
//A=>test()

快捷键alt+insert

image

image

箭头所指o是指override重写

小结note

重写:
1.方法名要相同
2.参数列表必须相同
3.修饰符:范围可以扩大public》protected》default》private
4.抛出的异常:可以缩小但不能扩大:ClassNotFoundEcpection --> Expection(big)

重写:子类的方法和父类要一致。方法体不同

为什么要重写:
    1.父类的功能子类不一定需要,或者不需要满足(太少
    Alt + Insert : override;


Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();

用法
Father f1 = new Son();
所有的内容是和new 后面的Student()一致的
有什么样的函数是取决于前面的 Student,Person,Object
    以及父类的public函数
相当于把前面Person 里面有的 方法 按Student的模板重写了一遍

不能重写的:
static
final   常量
private

测试

注解A的函数test------变成了继承

package com.oop.demo05;

public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.test();
        //父类的引用指向了子类

        B b = new A();//子类重写父类的方法
        //重写只能是public
        b.test();
    }
}

---------------------------------
package com.oop.demo05;

public class A extends B {
    
//    @Override//注解,有功能的注解!!
//    public void test() {
//        System.out.println("A=>test()");
//    }
}

----------------------------------
package com.oop.demo05;

public class B {

    public void test(){
        System.out.println("B=>test()");
    }
}


out:
    B=>test()
    B=>test()

注解B的函数test------变成了继承


---------------------------------
package com.oop.demo05;

public class A extends B {
    
    @Override//注解,有功能的注解!!
    public void test() {
        System.out.println("A=>test()");
    }
}

----------------------------------
package com.oop.demo05;

public class B {

//    public void test(){
//        System.out.println("B=>test()");
//    }
}


out:
    错误:找不到b的test

让方法变成static

---------------------------------
package com.oop.demo05;

public class A extends B {
    
    @Override//注解,有功能的注解!!
    public static void test() {
        System.out.println("A=>test()");
    }
}

----------------------------------
package com.oop.demo05;

public class B {

    public static void test(){
        System.out.println("B=>test()");
    }
}


out:
    A=>test()
    B=>test()

3. 多态

一个对象的实际类型是确定的-------------所有的内容是和new 后面的Student()一致的

new Person();
new Student();

可以指向的引用类型就不确定了,父类的引用指向子类--------------有什么样的函数是取决于前面的 Student,Person,Object

Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();

称为多态

package com.oop.demo06;

public class Student extends Person{
    public void eat(){
        sout("eat");
    }
    public void go(){
        System.out.println("go");
    }
}
-----------------------------------
package com.oop.demo06;

public class Person {
    public void run(){
        System.out.println("run");
    }
    public void go(){
        sout("????????????????")
    }
}
------------------------------------
package com.oop.demo06;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public abstract class Application {
    public static void main(String[] args) {
		Student s1 = new Student();
        Person s2 = new Student();
        Object s3 = new Student();
        
        s1.run();//run
        s2.run();//run
        s1.go();//go
        s2.go();//go
        s1.eat();//eat
        s2.eat();//错误
    }
}


解析:
    继承:父类有,子类继承父类函数
        s1.run();//run
        s2.run();//run
	重写:子类重写父类函数,父类的引用指向子类,故父类中的对应函数被子类覆盖
        s1.go();//go
        s2.go();//go
	子类有,父类没有,报错:找不到父类的引用
        s1.eat();//eat
        s2.eat();//错误//不能调用子类独有的方法
也就是说,对象能执行哪些方法,主要看左边的类型
错误解决方法------强制转化(高转低)
    ((Student)s2).eat();

注意事项:

  1. 多态是方法的多态,属性没有多态

  2. 父类和子类,有联系

  3. 类型转化异常:ClassCastException

  4. 存在条件:继承关系,方法需要重写

  5. 看前面的类型,是否为父类=子类,是否子类父类都有

    模板:Father f1 = new Son();

    1. 父类有:走父类
    2. 都有:重写,走子类
    3. 子类有:不应存在
  6. 多态中不会出现的修饰符

    1. static 是属于类的,不属于实例,和类相关
    2. final 常量无法改变
    3. private 私有方法无法被重写

instansof 和 类型转化

instanceof判断两个类型之间是否有关系

instanceof(实体)

insanceof

package com.oop.demo06;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public abstract class Application {
    public static void main(String[] args) {
        
        //instanceof
        //判断类型是否相似
        //模板:sout(X instanceof Y);
        //结果
        //1. 编译通过:是否存在父子关系,X能否转化为Y
        //2. 1/0:X的实际类型student是否是Student本身,子类或间接子类

        Object object = new Student();
        //Object > String
        //Object > Person > Teather
        //Object > Person > Student
        System.out.println(object instanceof Student);1
        System.out.println(object instanceof Person);1
        System.out.println(object instanceof Object);1
        System.out.println(object instanceof Teacher);0
        System.out.println(object instanceof String);0

        Person person = new Student();
        System.out.println(person instanceof Student);
        System.out.println(person instanceof Person);
        System.out.println(person instanceof Object);
        System.out.println(person instanceof Teacher);
        //System.out.println(person instanceof String);编译错误,相同等级下不能比较

        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);编译错误
    }
}

解释

boolean result = obj ``instanceof Class

​ 其中 obj 为一个对象,Class 表示一个类或者一个接口,当 obj 为 Class 的对象,或者是其直接或间接子类,或者是其接口的实现类,结果result 都返回 true,否则返回false。

  注意:编译器会检查 obj 是否能转换成右边的class类型,如果不能转换则直接报错,如果不能确定类型,则通过编译,具体看运行时定。

摘自作者IT可乐

类型转化

package com.oop.demo06;

import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;

public abstract class Application {
    public static void main(String[] args) {


        //强制转化P13,高转低,强制转化为子类,向下转型
        //高                   低
        Person obj = new Student();
        //obj.eat();报错
        
        Student student = (Student) obj;//强制转换
        student.eat();
        //以上两行可以直接((Student)obj).eat();
        //******(Student)obj.eat()是直接对函数obj.eat()进行强制转化,需要((Student)obj).eat();才能
        
        
        //低转高:子类自动转化为父类,可能会丢失本来的一些方法,向上转型
        Person person = student;
        //person.eat();//报错找不到eat()
    }
}

static关键词

静态属性

package com.oop.demo07;

//static
public class Student {
    private static int age;
    private double score;


    public static void main(String[] args) {
        Student s1= new Student();

        System.out.println(Student.age);//对于静态变量,我们推荐使用类.变量
        //System.out.println(Student.score);无法访问
        System.out.println(s1.score);
        System.out.println(s1.age);

    }
}

如果一个属性是静态的那么可以直接用Student.age访问,并且推荐使用类名访问

会在多线程里面用到

静态方法

package com.oop.demo07;

//static
public class Student {

    public void  run(){
        go();
    }
    public static void go(){

    }

    public static void main(String[] args) {
        new Student().run();
        Student.go();
    }
}

非静态方法可以调用静态方法

静态方法可以调用静态方法,但不能调用非静态

代码块

package com.oop.demo07;

public class /*fianl*/ Person {
    {
        System.out.println("匿名代码块");//代码块(匿名代码块
    }
    static {
        System.out.println("静态代码块");//静态代码块
    }
    public Person(){
        System.out.println("构造方法");
    }
	
    
    public static void main(String[] args) {
        Person person1 = new Person();
        System.out.println("============");
        Person person2 = new Person();
        //静态只生成一次
    }
}


out:
    静态代码块
    匿名代码块
    构造方法
    ===========
    匿名代码块
    构造方法

以上main()方法测试说明静态代码块只执行一次

不推荐使用匿名代码块,匿名代码块一般用来附初值

但在加载某些初始化数据的时候,会使用静态代码块

import

调用类里面函数

有时候在调用其他类里的函数时总是要写Math.random();

避免老是重复写Math,在最开头加

import static java.lang.Math.random;

称为静态导入包

通配符*

import static java.lang.Math.*;表示导入math里的所有函数

package com.oop.demo07;

//静态导入包
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());//在有静态导入包之后可以不用写Math
        System.out.println(PI);
    }
}

final常量

final之后,断子绝孙

package com.oop.demo07;

public class fianl Person {

}

-----------------------------------------------------
package com.oop.demo07;

//static
public class Student extends Person  不能继承final常量{
    
}

报错:无法继承final常量

抽象类

加了abstract就是抽象类

相当于抽象类写了用来约束的框架,然后由子类来帮我们实现框架的具体内容

不能new抽象类

子类必须实现父类的所有抽象函数

package com.oop.demo08;

public abstract class Action {
    //约束,自己只想写框架,下面的内容希望有人帮我们写(实现
    //只有方法的声明,没有实现
    public abstract void dpSomething();
    //1. 不能new抽象类
    //2. 抽象类中可以写普通方法
    //3. 抽象方法必须在抽象类中
    //抽象的抽象
}
package com.oop.demo08;

public class A extends Action {
    //抽象类的所有方法必须有继承他的子类,都要实现他的方法
    //除非子类也是抽象类,要子子类

    @Override
    public void dpSomething() {

    }
}

抽象类中可以写普通方法

package com.oop.demo08;
public abstract class Action {
    public void hello(){
        
    }
}

抽象类的意义:1提高开发效率,2进行约束,比如游戏,每创建一个角色只要继承这个抽象类,重写他的方法就行了。

抽象类存在构造器

接口

  • 普通类:只有具体实现

  • 抽象类:具体实现和规范(抽象方法)都有

  • 接口:只有规范,没有方法

  • 接口作用:实现约束和实现分离(进公司后,一般是面向接口编程,即写里面的方法

    ​ 是oop的精髓,是对对象的抽象

接口的本质是契约:即“如果你是……,那么你必须会……”

关键字interface

package com.oop.demo09;

public interface TimeService {
    void timer();
}

接口中的函数都是public abstract 修饰的

**接口中的属性都是public static final **,不过一般不会在接口里放常量

在idea中标灰,说明默认添加可以不写

image

应用

package com.oop.demo09;
//接口
public interface UserService {
    
    public static final int age = 99;//是个常量
    //不过一般没有人会在接口里面定义常量


    public void add(String name);
    public void delete(String name);
    public void query(String name);
    public void update(String name);
}
  • 接口都需要有实现
  • 接口可以重写多个
package com.oop.demo09;

//抽象类 extends
//类 可以实现接口 implements
//实现了接口的类,就要重写接口的方法
//接口可以重写多个!利用接口进行多继承
//不过 抽象类里可以有方法的实现,但是接口只有方法的定义
public abstract class UserServiceImpl implements UserService,TimeService{

    @Override
    public void run() {

    }

    @Override
    public void run(String name) {

    }

    @Override
    public void add(String name) {

    }

    @Override
    public void delete(String name) {

    }

    @Override
    public void query(String name) {

    }

    @Override
    public void update(String name) {

    }
}

接口的作用:
1.约束
2.定义一些方法,让不同的人来实现
3.public abstract
4.public static final
5.接口不能被实例化,接口中没有构造方法
6.implements 可以实现多个接口
7.必须重写接口中所有方法
8.总结博客

内部类

A类中定义B类,那么B类相对A而言是内部类

  • 可以获得外部类的私有属性
package com.oop.demo10;

public class Outer {
    private int id;
    public void out(){
        System.out.println("这是外部类的方法");
    }

    public class Inner{
            System.out.println("这是内部类的方法");
        }

        //获得外部类的私有属性
        public void getID(){
            System.out.println(id);
        }
    }

}
package com.oop.demo10;

public class Application {
    //new
    public static void main(String[] args) {

        Outer outer = new Outer();

        //通过外部类来实例化内部类
        Outer.Inner inner = outer.new Inner();
        inner.in();


        //匿名对象的使用,不用将实例保存到变量中
        new Outer().out();

    }

}

关于静态

注意!如果该内部类类静态,public static Inner{}

,则不能获得外部类的私有属性,因为static先生成,而此时 外部id还没有出生
解决方法:把id 也改成static

package com.oop.demo10;

public class Outer {
    private int id;

    public class static Inner{

        }
        public void getID(){
            System.out.println(id);//报错
        }
    }
}

可以有多个类

一个java只能有一个public class,但是可以有多个class,也可以有接口

相当于在大的java文件里面写了两个不同的类

也可以在方法里面定义类--局部内部类

package com.oop.demo10;

public class Outer {
    public void eat(){sout("I eat an apple")}
    public class Inner{};
    }
//局部内部类
    public void method(){
        class Inner{
            public void in(){}
        }
    }
}

//一个java类里只能有一个public
//但是可以有多个类
class A{
	psvm//可以在里面写main()方法,所以可以当成测试类
}

interface UserService{
    void hello();
}

匿名使用

package com.oop.demo10;

public class Application {
    //new
    public static void main(String[] args) {

        //匿名对象的使用,不用将实例保存到变量中
        new Outer().out();


        //匿名接口
        new UserService() {
            //重写
            @Override
            public void hello() {

            }
        };
        
        //接口也有返回值
        UserService userService = new UserService() {
            @Override
            public void hello() {

            }
        };
    }

}
posted @ 2021-07-29 16:10  星楓  阅读(76)  评论(0)    收藏  举报