面向对象编程的笔记

13 篇文章 0 订阅

面向对象编程的笔记

在面向对象中有两个重要的概念

  1. 类是一种抽象的概念 是具有某种共性 ---- 例如人类
  2. 对象 是一种具体的概念 是一个实例 就好像科比一样
  3. 科比 就是一个对象 职业篮球手 就是一个类

在类中有属性和方法 统称成员

成员方法

  1. 成员方法必须由对象(实例)来调用

  2. 成员方法想当于是一种对象的动作 比如 科比打篮球

    讨论一下方法的传参的机制
    1. 参数分为 形参 和实参
    2. 形参就可以看成一个变量
    3. 实参是一个具体的数据
    4. 形参是方法和外界交互的接口
  3. 每个成员方法的级别是一样的 不能在方法中再定义方法

  4. 对于赋值的说明

     1. 如果是基本数据类型就直接拷贝数据
        2. 是引用数据类型就直接将在堆中的地址 拷贝进去
        3. 基本数据类型是独立的 而引用数据类型是共享的
    

方法的递归 很重要!!!(未完成)

这里缺很多代码 要补充代码

方法的重载和重写的对比

  1. 对于方法的重载就是 方法名一样 参数列表类型不一样 其他自便

  2. ***重写***的要求就比较多了

    1. 首先  方法名 必须一样 参数列表类型 必须一样
       2. 返回值类型是对应的或其的子类
       3. 抛出的异常不能多
       4. 访问修饰符范围 不能变小
       5. ***最重要的是!!!!!!***
       6. 重写必须是发生在有继承关系的两个类中
       7. 重载发生在本类中
    

可变参数(形参)

  1. 就是参数列表的参数个数不确定
  2. 其本质就是一个数组
  3. 传进来的实参 可以是一个***数组***
package OverJava;

public class Unkown {
    public static void main(String[] args) {
        say(1,2,4,5,6,7,8,9);
    }
    public static void say(int... nums)
    {
        for (int i = 0; i < nums.length; i++)
        {
            System.out.println("第"+(i+1)+"个值为"+nums[i]);
        }
    }

}

注意

  • 可变参数可以和普通类型参数放在一起 但是可变参数类型必须在最后
  • 每一个方法必须只能有一个可变参数

作用域

java 中 变量分为全局变量(属性) 和 局部变量

  • 局部变量 不能修饰符
  • 全局变量 可以修饰符
  • 局部变量在方法中且 只能供该方法使用
  • 全局变量 可以在本类调用 亦可以在 其他类调用
  • 全局变量有默认值 局部变量没有
  • 全局变量 随着 对象的创建而创建 消亡而消亡
  • 局部变量 随着 他的代码块的执行而创建 结束而消亡

构造器

用于 对实例的初始化

  1. 是一种特殊的方法
  2. 方法名和类名相同 没有返回值
  3. 创建对象是自动 调用构造器

this 关键字

  1. this 指的是当前对象 看图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vjYVmHmr-1636375616845)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211106112346109.png)]

记住一句话 this 就是当前对象

this() 调用本类的其他构造器

package 包

包他的本质就是一个文件夹

方便管理 在不同的包内 可以同名的类

访问修饰符

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gWP4sdYL-1636375616848)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211106113346244.png)]

对于类而言他只有 public 和 默认的修饰符

再次强调局部变量不能有修饰符

面向对象的三大特征

  1. 封装
  2. 继承
  3. 多态

封装

  1. 就是将属性私有化 提供公有的方法 来进行 保护
  2. 一般 有getXXX(); setXXX();

继承

  1. 就是将 很多类中还有一些共同的方法和属性 再进行抽象 放在一个类里 那么这个类就叫做父类
  2. 关键字 extends
  3. java 只支持单继承
  4. 子类继承了父类所有的方法和属性 但是私有化的不能直接访问 可以通过 公共的方法来访问
  5. 子类必须调用父类的构造器来初始父类的属性和方法
  6. 创建子类对象是父类构造器会先调用先初始化父类的成员 在初始化 子类的成员
  7. 但是 对象还是只有一个子类的对象 只是在子类对象里 初始化了父类的方法和 属性

看图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tJIKYORB-1636375616852)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211106115246776.png)]

super 关键字

super 关键字 就是用来调用父类的属性和方法 但是要遵守 一定的访问权限

super()

  1. 用来调用父类的构造器的
  2. 在子类的构造器中默认就有一个无参构造器 super(); 且在第一行
super 和 this 的比较

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ONRZ0Z2-1636375616855)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211106120549440.png)]

其实原因是在对象实例里 父类的成员 和子类的成员 都是互相独立的

image-20211106120952271

多态

何为多态 多种状态

  1. 方法存在多态
  • 发放的重写和重载 就体现了多态 (同一方法名 不同的对象调用效果不同 参数不同效果不同)

  • 参数的多态

             1. 形参类型为父类类型 ***实参类型可以为其子类***
                2. 实质还是向上转型
    
  1. 最重要的是***对象的多态***
对象的多态
  1. 对象分为编译类型 和 运行类型

  2. 编译类型 是靠编译器来检查的 编译器不检查运行类型

  3. Person person = new Student();//Student  继承了 Person
    

​ 编译类型就是 Person 而运行类型是Student 编译器检查Person 不会检查 Student

  1. 其实向上类型转换就是 -------- 基本类型数据的自动转换
  2. 向下类型转换就是---------基本类型数据的强制转换
Person person = new Student();//Student  继承了 Person
Student student = (Student) person;// 向下转型

谈谈我对父类引用指向 子类对象的理解

  1. 首先 编译器只看 编译类型 看到是父类就检查代码中 有关父类的属性和方法是否正确
  2. 这就是为什么 用父类引用指向不能用 子类独有的方法了
  3. 想用子类独有的方法就的用子类类型的引用来指向对象
  4. 至于为什么这样 我是这样理解的 (借鉴了基本数据类型) 可能是在内存中开的空间或者其他哪里有点不一样
  5. 用 instanceOf() 来判断是不是该类型 或其子类
Person person = new Student();//Student  继承了 Person
Student student = (Student) person;// 向下转型
student instanceOf(Person);//true
student instanceOf(Student);//true
Object obj = new Object();
obj instanceOf(Person);//false

谈谈Object

== 和 equals 的区别
  1. == 是一个比较运算符 equals() 是一个方法
  2. == 既可以比较 基本数据类型 也可以比较 引用数据类型
  3. 基本数据类型的话就是看值是否相等
  4. 引用数据类型也是看值是否相等 只是这个值 是地址 所以就是看 是否为通一对象

equals()

  1. 他是Object的一个方法 只能用来判断引用数据类型
  2. 如果没有被重写的话那么就是判断 引用数据类型 的地址是否一致 是否为同一对象
  3. 重写了的话 那么就是判断内容是否一致 比如在包装类中 和String中

这里简单的谈谈 hashCode 和 toString 以及 finalize

  1. hashCode 将对象的地址装换为哈希码值
  2. toString 方法是将全类名+ @ + 哈希值的16进制
  3. finalilze 方法 是JVM 认为他是一个垃圾对象时 在销毁他之前就调用他的finalize方法

断点调试的方法(未完成)

这里以后来补充!!!

类变量和类方法 (静态方法 和 静态变量)

  1. 有时我们希望在同一个类中 可以共享一些数据 和 方法 这时类变量就发挥了作用
  2. 类变量是静态的 用(static)来修饰

看图

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ma4POLVr-1636375616856)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211106152449087.png)]

  1. 关于类变量的访问
  • 用类名.类变量名
  • 也可以用 对象名.类变量名
  • 类变量是隶属于 类的 所以没有对象也可以访问
  1. 类变量是所该类对象共享的 而实例变量是每个对象独享的
  2. 类变量是在类加载时就已经初始化了 随着类的加载而加载 类的消亡而消亡

类方法的思想大致和类变量差不多

  • 类方法一般用于做工具类 可以再不创建对象就可以使用
  • 如 Math.sqrt();

类方法和成员方法的比较

  1. 类方法 和普通方法 都是随着类的加载而加载 将结构信息存放在方法区
  2. 类方法中不能有this and super
  3. 类方法只能访问静态方法和静态变量
  4. 成员方法既可以访问静态的也可以访问非静态的
  5. 他们都要遵循访问权限

对main() 方法来解释解释

  1. public static void main(String[] args){}
    
  2. main() 方法是由JVM调用的jvm肯定和你写的main()类文件不在一起 所以用public

  3. jvm 调用的时候不用创建对象 所以是静态的

  4. void 调用main()方法 不期待有返回值 所以就 是void

  5. String[] 就是一个字符串数组 保存 Java命令是传递给所运行类的参数

几点说明

  1. main方法可以直接调用 该类的静态方法和静态变量 但是不能用成员方法和成员变量
  2. 要用该类的成员方法和成员变量 必须创建对象

代码块

  1. 代码块的修饰符只能有static
  2. 代码块中的代码可以是任何代码
  3. 代码块相当于是一种对构造器的补充 可以来做初始化工作
  4. 比如 每个构造器中有许多相同的语句 可以抽取到初始化块中 来提高代码复用性
  5. 代码块调用的数据优先于构造器
  6. static 代码块 只在类加载时被执行 并且只执行一次 如果是普通代码块是每创建对象 调用一次
  7. 这里说明一下什么时候类被加载 (很重要!!!)
    • 创建对象实例
    • 使用子类的对象实例 父类也会被加载
    • 使用类的静态成员时
  8. 普通代码块 在创建实例时 会被隐式的调用
  9. 如果普通代码块中只是用了静态成员时 普通代码块并不执行

创建对象时 在一个类的调用顺序

  1. 静态代码块 和 静态属性初始化的优先级是一样的 他们同时存在 按照他们的顺序来
  2. 普通代码块 和 属性初始化 的优先级也是一样的 他们 同时存在 就按照他们的顺序来
  3. 最后再是构造方法

再看看构造器中内部结构(一种理解)

class A
{
    public A()
    {
        //这里隐藏了执行要求
        //(1) super();
        //(2) 调用普通代码块
        //然后再执行构造器中的内容
    }
}

在有继承关系中的调用顺序

  1. 父类的静态代码块 和静态变量初始化
  2. 子类的静态代码块 和 静态变量初始化
  3. 父类的普通代码块 和 成员变量初始化
  4. 父类的构造器
  5. 子类的普通代码块 和 普通成员变量初始化
  6. 子类的构造器

扩展 — 单例模式 (未完成)

final 关键字

final的中文意思是 最终的最后的

  1. final 可以修饰 类 属性 方法 局部变量
  2. 这里插一嘴 能修饰局部变量就好像只有 final (我现在的认知可能不全面)
  3. final 修饰的类 不能继承
  4. final 修饰的方法 不能 被重写
  5. final 修饰的变量不能被更改

抽象类

由于某些因素 可能使方法有不确定性

  1. 这是就需要一个抽象方法
  2. 包含抽象方法的类必须是抽象方法
  3. 关键字是 abstract
  4. 抽象方法没有方法体
public abstract void say();  // {} 有花括号就是有方法体
  1. 抽象类不能被实例化 (况且实例化也没有意义 里面的方法是空的)

  2. 抽象类里可以没有抽象方法 但是***有了抽象方法必然是抽象类***

  3. 抽象方法 本质还是一个类 可以有 非抽象方法 构造器 (我不是很理解) 静态属性…

  4. 如果一个类继承了抽象类 那么他必须重写里面的全部抽象方法

  5. 抽象方法不能被private final static 修饰 (因为与重写违背)

这里有个抽象类的最佳实践(要补充!!!)

接口

接口就是一些没有实现的方法 封装到一起 当某个类要使用时 在根据具体的逻辑来重写

基本语法

interface S
{
    //属性
    //抽象方法 (可以不用abstract 来修饰)
}
class A implements S
{
    //自己的成员
    //必须实现S接口的方法
}

接口是抽象的抽象类 在jdk7 以前接口中的方法不能有方法体

jdk8 以后可以有静态方法 默认方法(default) 换句话说就是在接口中可以有具体的方法实现了

接口可以规范一些标准(现在我是小白还不是很明白接口的神奇所在)

注意

  1. 接口不能被实例化 (因为接口是更加抽象的抽象类)
  2. 接口中的方法全是public 在接口中可以不能abstract 来修饰
  3. 普通类实现接口必须实现全部的抽象方法
  4. 抽象类实现接口 可以不用实现接口的方法
  5. 一个类可以有多个接口
  6. 接口的属性只能是final 而且是public static final
  7. 接口不能继承其他类 但可以继承其他接口
  8. 接口的修饰符只能是public 和默认

接口和继承的区别

这里先简单解释解释一下

继承满足的是 is xxx

接口满足的是 like xxx

我也是个小白 没有什么代码积累也不是很懂

  1. 对于接口 他更加的灵活 可以更好的规范和扩展
  2. 而继承 主要是解决代码的复用性和维护性

接口的多态(待补充)

简单说一下 接口的引用可以 指向实现了该接口的类

可以这样想 接口也只是一个比抽象类更抽象的类(实质我不知道可以这样理解)

所以 就可以用 接口的引用来指向 实现了该接口的类的对象

先简单这样解释 以后来补充

内部类

类中的五大成员 属性(字段) 方法 构造器 代码块 内部类

内部类分为

  1. 局部内部类
  2. 匿名内部类(很重要!!!)
  3. 成员内部类
  4. 静态内部类

总结一下似乎就只有 方法不能嵌套

局部内部类

局部内部类在外部类的局部位置上 比如方法中 并且有类名

  1. 局部内部类 可以访问外部类的全部属性 包括 私有的 (其实也很好理解 局部内部类实质也是在外部类在 在当前类中是可以访问 私有的成员的)
  2. 不能添加访问修饰符 可以加 final 的关键字 (局部内部类就相当于一个局部变量)
  3. 他的作用域仅仅在定义他的方法中或者代码块里
  4. 局部内部类 访问 外部类成员 (直接访问)
  5. 外部类 访问 局部内部类 (通过创建对象 在访问 但***还是得在他的作用域内***)
  6. 外部其他的类 不能访问 局部内部类
  7. 如果外部类 和 局部内部类 重名了 就遵循就近原则 想要访问外部类的成员 就用(外部类名.this.成员)

这里缺代码

匿名内部类(很重要!!!)

  1. 本质还是个类
  2. 内部类
  3. 还是一个对象
  4. 该类没有名字
//基本语法
//new 类and 接口名(参数列表)
          {类体}; // 分号不要少

其他注意事项与局部内部类一样

代码演示

package OverJava;

public class UnName {
    public static void main(String[] args) {
        //演示三种匿名内部类
        //抽象类
        Animal dog = new Animal(){
            public void move()
            {
                System.out.println("狗在移动");
            }

            public void eat()
            {
                System.out.println("狗在吃骨头");
            }

            public  void sleep()
            {
                System.out.println("狗在呼呼睡大觉");
            }
        };
        dog.eat();
        dog.move();
        dog.sleep();
        System.out.println("狗对象的类"+dog.getClass());

        //普通类

        Father father = new Father("jack",39){

        };
        System.out.println(father.info());
        System.out.println("father对象的类"+father.getClass());

        //接口

        Usb meizuUsb = new Usb(){
            @Override
            public void workStart() {
                System.out.println("魅族手机接口开始工作");
            }

            @Override
            public void workEnd() {
                System.out.println("魅族手机接口停止工作");
            }
        };
        meizuUsb.workStart();
        meizuUsb.workEnd();
        System.out.println("meizuUsb对象的类"+meizuUsb.getClass());
    }
}

//这是一个抽象类

abstract class Animal
{
    public abstract void move();
    public abstract void eat();
    public  abstract void sleep();
}

//这是一个普通类

class Father
{
    private String name;
    private int age;

    //构造器
    public Father(String name, int age)
    {
        setName(name);
        steAge(age);
    }


    //setter and getter

    public String getName()
    {
        return name;
    }

    public void setName(String name)
    {
        this.name = name;
    }

    public int getAge()
    {
        return age;
    }

    public void steAge(int age)
    {
        if (age <= 0)
        {
            System.out.println("你的年龄值不符合逻辑(已经赋值成默认值)");
            this.age = -1;

        }
        this.age = age;
    }

    public String info()
    {
        return getName() + "你好,"+getAge()+"这就是你的年龄";
    }
}

//这是一个接口

interface Usb
{
    void workStart();
    void workEnd();
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bhLLupkr-1636375616859)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211107142735123.png)]

匿名内部类用来简化开发的(注意代码的积累)

匿名内部类的最佳实践

当做实参直接传递简洁高效(对于现在的我而言可能感觉不大)

代码实例

package OverJava;

public class UnNameGood {
    public static void main(String[] args) {
        Master master = new Master();
        master.feed(
                new Animal_("小哈希"){
                    @Override
                    String eat() {
                        return this.name +"吃骨头";
                    }
                }
        );
    }
}

//定义一个类

class Master
{
    public void feed(Animal_ animal)//这里缺参数
    {
        System.out.println("主人在喂"+animal.eat());
    }

}

//定义一个抽象类(动物)
abstract class Animal_
{
    String name;

    public Animal_(String name) {
        this.name = name;
    }

    abstract String eat();
}

package OverJava;

public class BestUnName {
    public static void main(String[] args) {
        Phone pandaer = new Phone("PANDAER", "17度灰");
        pandaer.alarmclock(
                new Bell(){
                    @Override
                    public String ring() {
                        return "小懒虫起床了";
                    }
                }
        );
    }
}

//模拟闹钟响铃

//定义一个接口
interface Bell{
    String ring();
}

//定义一个手机类
class Phone
{
    String name;
    String color;
    String masterName = "故事与酒";

    //构造器
    public Phone(String name, String color)
    {
        this.color = color;
        this.name = name;
    }

    //闹钟方法
    public void alarmclock(Bell bell)
    {
        System.out.println(color+"的"+name+"手机的闹钟发出声音:"+bell.ring()+",吵醒了"+masterName);
    }

}

成员内部类

成员内部类定义在外部类成员的位置,不能有static修饰

  1. 可以直接访问外部类的所有成员 包括 私有的
  2. 可以添加任意访问修饰符 因为他的地位是一个成员(可以看成一个成员变量和成员变量的集合)
  3. 既然是个成员 那么他的作用域就是在整个外部类;

外部类 --------- 内部类 : 要创建内部类的对象 再访问

内部类----------外部类 : 直接访问简单粗暴

外部其他类也能访问成员内部类 :

  1. 可以再外部类里写一个方法来返回一个内部类的实例(对象)
  2. 也可以直接创建对象
Outer.InerClass iner1 = new Outer().new InerClass();

代码演示

package OverJava;

public class InerClass {
    public static void main(String[] args) {
        Mater1 mater1 = new Mater1();
        mater1.say();
        mater1.say2();
    }
}

//这是外部其他类
class Mater1
{
    //第一种方式
    Outer outer = new Outer();
    Outer.InerClass iner = outer.getInerClass();

    //(第二种方式)
    Outer.InerClass iner1 = new Outer().new InerClass();
    public  void say2()
        {
            System.out.println("say2说的");
            iner1.say();
        }

    public void say()
    {
        iner.say();
    }
}

//这是一个有成员内部类的类
class Outer
{
    String name;
    int age;

    class InerClass
    {
        public void say()
        {
            System.out.println("我说EDG牛逼!!!");
        }

    }

    //在外部类返回一个inert的对象(一种方式)
    public InerClass getInerClass()
    {
        return new InerClass();
    }

}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rFZC63h8-1636375616861)(C:\Users\故事与酒\AppData\Roaming\Typora\typora-user-images\image-20211107152939927.png)]

(上图不是特别准确我也是小白)

静态内部类

  1. 静态内部类 在外部类的成员位置上 有static 修饰
  2. 他还是可以添加访问修饰符 毕竟他的地位是一个成员
  3. 既然是成员了那当然他的作用域就是 外部类的全部了晒
  4. 静态内部类 可以直接访问外部类的静态变量和方法 但不能直接访问 外部类的成员方法和变量(可以通过new 对象)

外部类 --------- 静态内部类 : 要创建对象再访问

外部其他类 ------- 静态内部类 : 方法也有两种

  1. 第一种还是 在外部类创建一个方法来返回一个静态内部类的对象
  2. 第二种
Outer.iner iner1 = new Outer.iner();

我的理解 : 静态内部类的构造器 相当于一个静态的 方法 可以直接通过类名.方法名调用 所以不能创建外部的对象实例(理解不一定准确)

代码实例

package OverJava;



public class StaticInerClass {
    public static void main(String[] args) {
        OuterOther outerOther = new OuterOther();
        outerOther.iner2.say();

        System.out.println("=========");

        outerOther.iner3.say();
    }
}

//这是一个外部其他类
class OuterOther
{
    //调用静态内部类的第一种方式
    Outer2.Iner2 iner2 = Outer2.getIner2();

    //第二种方式
    Outer2.Iner2 iner3 = new Outer2.Iner2();
}

//定义一个含有静态内部类的类
class Outer2
{
    String name;
    static class Iner2
    {
        static String name = "小哈希";
        public static void say()
        {
            System.out.println(name + "你好呀" );
        }
    }
    public static Iner2 getIner2()
    {
        return new Iner2();
    }
}

总结结束语

代码的能力始终不过关

有了强大的理论还要有足够的实践

写代码时要全神贯注 不能走神

我亦无他, 唯手熟尔!!!
理解不一定准确)

代码实例

package OverJava;



public class StaticInerClass {
    public static void main(String[] args) {
        OuterOther outerOther = new OuterOther();
        outerOther.iner2.say();

        System.out.println("=========");

        outerOther.iner3.say();
    }
}

//这是一个外部其他类
class OuterOther
{
    //调用静态内部类的第一种方式
    Outer2.Iner2 iner2 = Outer2.getIner2();

    //第二种方式
    Outer2.Iner2 iner3 = new Outer2.Iner2();
}

//定义一个含有静态内部类的类
class Outer2
{
    String name;
    static class Iner2
    {
        static String name = "小哈希";
        public static void say()
        {
            System.out.println(name + "你好呀" );
        }
    }
    public static Iner2 getIner2()
    {
        return new Iner2();
    }
}

总结结束语

代码的能力始终不过关

有了强大的理论还要有足够的实践

写代码时要全神贯注 不能走神

我亦无他, 唯手熟尔!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值