Java学习(一)---面向对象(上)
Java学习(一)---面向对象(上)
pyq答应各位,这期博客更Springboot相关内容
但由于博主已经忘了很多Java知识(惭愧 (•̅灬•̅ )
因此需要复习(学习)一些前置知识
基础概念
其实就是博主比较菜,以及喜欢碎碎念
-
Java在内存中总是使用Unicode表示字符
-
单引号->字符,双引号->字符串
-
三双引号->多行字符串(Text Blocks) ...方便后续写SQL
-
字符串不可变,变动的只是指向字符串的指针,为null时不指向,为“”时指向空
-
printf()可以让Java像C一样格式化输出(好好好
-
for each 可以更好地遍历获取值(正常的for只是按照索引访问)
-
JVM可以接收用户输入的(...)命令行参数
string[] args
传给main方法
面向对象
emmm真的忘了很多...
- 面向过程:按部就班,这一步完了下一步
- 面向对象:实例化一个对象类,然后调用它有的方法
-
方法
-
由于需要封装成员变量,因此我们要使用方法来设置和获取成员变量(get,set)
-
private 方法可以被 类内部的方法调用(public or private)
-
this变量始终指向当前实例,因此this.field 可以访问当前实例的成员变量
-
没有命名冲突时,可省略this,重名时必须加上
-
public void a(Type... b) 即可输入Type 类型数组(可变参数)
- 如果使用 Type[] 传入有两个缺点
- 需要自己构建新的数组类型Type[],再进行传参
- 可以传入null
- 如果使用 Type[] 传入有两个缺点
-
如果传入的是数组(字符串),那么在类操作外部修改内容,实例的成员变量也会发生改变,因为传入的其实是指向数组的指针,而不是指针指向的内容(例子如下)
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 关键字
final
类: 如果一个类被声明为final
,则该类不能被继承。也就是说,不能创建该类的子类。final
方法: 如果一个方法被声明为final
,则该方法不能被子类重写(覆盖)。子类无法改变该方法的实现。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继续更新(复习)面向对象
但可能会先更一篇爬虫收尾,打工生活终于要暂停一段时间了。。。心累
参考资料
今日小知识
Nginx反向代理和DNS解析的区别
看上去好像差不多,都是绑定服务器和域名,但实际上还是不太一样的
DNS解析:将域名转换为对应的IP地址的过程。当你在浏览器中输入一个域名时,系统会通过DNS解析找到该域名对应的IP地址,然后将请求发送给该IP地址对应的服务器。
Nginx反向代理:当客户端发送请求时,请求首先到达Nginx服务器,然后Nginx服务器根据配置将请求转发到后端的某个服务器上,后端服务器处理请求并将结果返回给Nginx,最后Nginx将结果返回给客户端。