Java学习(一)---面向对象(上)

pyq答应各位,这期博客更Springboot相关内容

但由于博主已经忘了很多Java知识(惭愧 (•̅灬•̅ )

因此需要复习(学习)一些前置知识

基础概念

其实就是博主比较菜,以及喜欢碎碎念

  • Java在内存中总是使用Unicode表示字符

  • 单引号->字符,双引号->字符串

  • 三双引号->多行字符串(Text Blocks) ...方便后续写SQL

  • 字符串不可变,变动的只是指向字符串的指针,为null时不指向,为“”时指向空

image-20230823192138682.png

  • printf()可以让Java像C一样格式化输出(好好好

  • for each 可以更好地遍历获取值(正常的for只是按照索引访问)

  • JVM可以接收用户输入的(...)命令行参数string[] args传给main方法

面向对象

emmm真的忘了很多...

  1. 面向过程:按部就班,这一步完了下一步
  2. 面向对象:实例化一个对象类,然后调用它有的方法
  • 方法

    • 由于需要封装成员变量,因此我们要使用方法来设置和获取成员变量(get,set)

    • private 方法可以被 类内部的方法调用(public or private)

    • this变量始终指向当前实例,因此this.field 可以访问当前实例的成员变量

    • 没有命名冲突时,可省略this,重名时必须加上

    • public void a(Type... b) 即可输入Type 类型数组(可变参数)

      • 如果使用 Type[] 传入有两个缺点
        1. 需要自己构建新的数组类型Type[],再进行传参
        2. 可以传入null
    • 如果传入的是数组(字符串),那么在类操作外部修改内容,实例的成员变量也会发生改变,因为传入的其实是指向数组的指针,而不是指针指向的内容(例子如下)

      public class Main {
          public static void main(String[] args) {
              Person p = new Person();
              String[] fullname = new String[] { "Homer", "Simpson" };
              p.setName(fullname); // 传入fullname数组
              System.out.println(p.getName()); // "Homer Simpson"
              fullname[0] = "Bart"; // fullname数组的第一个元素修改为"Bart"
              System.out.println(p.getName()); // "Homer Simpson"还是"Bart Simpson"?
          }
      }
      
      class Person {
          private String[] name;
          public String getName() {
              return this.name[0] + " " + this.name[1];
          }
          public void setName(String[] name) {
              this.name = name;
          }
      }
      
    • 注意,String传进去是不会变化的,String只不过是拷贝值进去,String[]传入的是引用(内存地址)

    • 总结: String 是不可变的类型,传递给方法时不会受到外部变化的影响。而 String[] 是可变的类型,传递给方法时会受到外部变化的影响。

  • 构造方法

    • 即,一个与对象类同名的方法,用于在创建对象时传入成员变量(减少set 成员变量的步骤)

    • 构造方法是每个类都有的,就算没有设置,也会有默认构造方法

      • class Person {
            public Person() {
            }
        }
        
      • 可是一旦定义了构造方法,就会将默认的删去,想要两者共存的话,必须定义两次。(既可以new Person(),又可以new Person(Name)
      • 成员变量未通过构造方法初始化时,会采用默认值

      引用类型的字段默认是null,数值类型的字段用默认值,int类型默认值是0,布尔类型默认值是false

      • 多重构造方法之间可以相互调用

        	public Person(String name) {
                this(name, 18); // 调用另一个构造方法Person(String, int)
            }
            public Person() {
                this("Unnamed"); // 调用另一个构造方法Person(String)
            }
        }
        
  • 方法重载

    • 和多重构造方法类似,普通方法也可以多次定义,即方法重载

    • 其实也就是传入不同参数,调用同名方法中的对应者

      int indexOf(int ch):根据字符的Unicode码查找;

      int indexOf(String str):根据字符串查找;

      int indexOf(int ch, int fromIndex):根据字符查找,但指定起始位置;

      int indexOf(String str, int fromIndex)根据字符串查找,但指定起始位置。

  • 继承

    • 在类的成员变量和方法大量重复的时候使用

    • 方便代码复用,减少工作量

    • 可以继承父类的成员变量和方法,定义新的成员变量和方法

    • 重写父类方法时,原方法在父类作用领域不变,新方法在子类对象(运行时)调用生效

    • 向上转型实际上是把一个子类型安全地变为更加抽象的父类型

    • 注意:如果声明类型为父类,指向的对象却是继承后的子类,那么其静态类型为父类,运行时指向子类,调用方法时会调用子类的方法 即下文讲的多态

      Parent polymorphicReference = new Child();
      polymorphicReference.printMessage(); // Output: "This is the child class."
      

      尽管声明类型是 Parent,但因为实际上 polymorphicReference 指向的是 Child 类的实例,所以调用 printMessage 方法时会执行 Child 类中的重写实现

    • 一旦编写继承树后,建议使用protected关键字将 成员变量 封装在继承树内部

    • 子类重写构造方法时,必须使用super(*)调用父类构造方法

    • 使用sealed 关键字 和 permits 可以限制可以继承该类的子类名字

    • 向下转型为,把一个父类类型强制转型为子类类型。但可能出现一开始已经定义好了 person a = new person() 然后强制转为子类 b=(student) a 而报错

    太TM抽象了,转来转去有必要吗。。。,一开始还是能懂的,parent a =new child() 这样可以调用子类方法和变量,但转的意义何在?

    GPT:在具体的情况下只涉及到子类对象,直接使用子类类型的引用更加简洁明了。

    使用 Parent a = new Child(); 则更多用于在需要多态性或父类引用的特定场景中。

    大概意思是,如果我写了函数传参是父类对象,但我希望传一个子类,或者父类对象拥有子类属性(变量、方法) 此时可以这样用

    将父类对象指向子类,将子类赋值给父类-------向上转型

    • instanceof可以确定是否属于某类 ,方便类型转换(向下)

      Parent parent = new Child();
      if (parent instanceof Child) {
          Child child = (Child) parent; // 安全地将父类引用转换为子类引用
      }
      
    • 注意区别类和类之间的关系(组合、继承)(组合可以理解成包含,即类内包含一个类成员变量)

  • 多态

    • 多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。

    • 父子同名同参的方法,即子类覆写了父类方法

    • 且在运行时 Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。

    • 同名不同参数,参考上文的重载函数

      @Override 可以让编译器检查是否进行了正确覆写

    • 为什么要使用多态?

      public void runTwice(Person p) {
          p.run();
      }
      

      如当前例子,我们只看当前代码,看不出传入的类型到底是Person 还是 Person 的 子类,因此,多态的机制就可以实现,在运行时,动态决定调用该类型的方法。

      如此一来,我们就不用去判断类型来决定如何执行程序(面向过程)而是可以写一个通用程序,让编译器在运行时自己判断类型,然后调用其本身的方法

    • 简单来讲,就是如果有一个方法(比如花钱),每个人的开销不同,因此传入参数相同时,对应自己的类型会自动处理,(你每天花多少和我每天花多少很大概率不同,如果相同就可以归为一类了

      然后这还并不能体现出多态的优势,得复合运用才能体现。比如我这又有一个计算余额的方法,传入参数为所有人的父类,那么计算余额时,统计花销就会执行对应子类的方法。

    • 同时,如果有新的一类人,有新的花销,我们只需要新建一个子类,覆写一个子类花销方法即可

    • 这样就可以不用修改父类,而增加更多的多样性

  • Tips

    • Object 方法

      • toString():把instance输出为String
      • equals():判断两个instance是否逻辑相等;
      • hashCode():计算一个instance的哈希值。

    示例

    // 显示更有意义的字符串:
        @Override
        public String toString() {
            return "Person:name=" + name;
        }
    
    • Super 的调用

    可以在子类方法中,通过super调用父类(被覆写)方法

    • final 关键字

      1. final 类: 如果一个类被声明为 final,则该类不能被继承。也就是说,不能创建该类的子类。
      2. final 方法: 如果一个方法被声明为 final,则该方法不能被子类重写(覆盖)。子类无法改变该方法的实现。
      3. final 变量: 如果一个变量被声明为 final,则该变量在初始化之后不能再被赋予新的值。这个变量在使用前必须被初始化。

示例

复习。。。

public class Main {
    public static void main(String[] args) {
        Person a = new student("paul");
        Person b = new Person("pepper");
        a.run();
        b.run();

        System.out.println("another test");

        test(a,b);
    }
    public static void test(Person... p){
        for (Person itme:p){
            itme.run();
        }
    }
}
class Person {
    private String name;

    public void run (){
        System.out.println("i m dad");
    }
    public Person(String name){
        this.name=name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
class student extends Person{
    protected int score;

    public void run(){
        System.out.println("i m son");
    }
    public student(String name){
        super(name);
    }
    public student(String name,int score){
        super(name);
        this.score=score;
    }

}

这篇先这样吧,两周没写博客了,属于是摆大烂了。

╮(๑•́ ₃•̀๑)╭

下篇Java继续更新(复习)面向对象

但可能会先更一篇爬虫收尾,打工生活终于要暂停一段时间了。。。心累

参考资料

廖雪峰Springboot教程

今日小知识

Nginx反向代理和DNS解析的区别

看上去好像差不多,都是绑定服务器和域名,但实际上还是不太一样的

DNS解析:将域名转换为对应的IP地址的过程。当你在浏览器中输入一个域名时,系统会通过DNS解析找到该域名对应的IP地址,然后将请求发送给该IP地址对应的服务器。

Nginx反向代理:当客户端发送请求时,请求首先到达Nginx服务器,然后Nginx服务器根据配置将请求转发到后端的某个服务器上,后端服务器处理请求并将结果返回给Nginx,最后Nginx将结果返回给客户端。

文章作者: P4ul
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 打工人驿站
后端 java
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝