方法的返回值类型:
有返回值:用return返回即可 ,返回的可以是个double,int,也可以是个对象等等
无返回值:一般没有return
注:无返回值的也可以加return,只不过它的后面不能加任何东西。
java变量:
- 成员变量:在类内方法外的变量,没有static修饰符修饰(堆内存)
- 类变量:在类内方法外的变量,且有static修饰符修饰(方法区)
- 局部变量:在方法内或者方法参数列表内的(栈内存)
java变量的默认值:
局部变量没有默认值(没有初始化就使用,会出错),成员变量和类变量都是有默认值的。如下:(注意,string类型属于引用类型的数据)
java方法:
- 类方法:类内有static修饰,既可以通过类名访问,也可以通过创建对象去访问。(方法区)
- 成员方法:类内没有static修饰,只能通过创建对象去访问。(方法区)
- 构造方法:在创建对象的时候就会启动的方法(方法区)
- 注:类方法只能调用类方法和类变量,成员方法可以调用类方法、类变量、成员方法和成员变量,构造方法可以调用类方法、成员方法,成员变量和类变量以及其他的构造方法(this关键字去调用)
-
补充:静态代码块:
- 方法传参:对于基本数据类型传的是参数的赋值品,也就是说方法对参数的修改不会改变原来的值;对于引用类型传参,传递的是地址,方法对参数的修改会导致原来的值发生改变
java虚拟机的运算加载的底层逻辑:
- 方法区:当程序启动的时候,虚拟机首先加载.class字节码文件到方法区。静态的变量和所有的方法也随之加载到方法区(且只加载一次)
- 栈内存(方法栈):方法运行时使用的内存,比如 main 方法运行,进入方法栈中执行。
- 堆内存:存储对象或者数组,new 来创建的,都存储在堆内存。
详解:
- 当程序启动的加载时候,首先把.class的字节码文件加载到方法区,包括静态变量和所有的方法(构造,成员,类,mian方法)
- 随后,main方法中的变量和方法压到栈里面,从头开始在栈里面执行main方法。
- 对于局部变量来说,他们会伴随着他们所属的方法在栈里面而存在消失。
- 当new创建对象的时候,首先在堆内存里面开辟一个空间,同时创建对象的成员变量,此时每个成员变量都是默认值,成员方法的指向(地址)方法区的成员方法(并不会在堆内存里面去复写),然后构造方法压到栈中实现对成员变量的赋值。对象的地址指向栈里面的局部变量。
- 当要访问某个成员方法的时候,先在堆里面找到这个方法的引用,再找到相应方法区内的字节码,并把字节码加载到栈中执行。执行完后释放相应的内存
- 对于类方法,就可以直接再方法区内找到相应的字节码,压到栈中执行就可以了。
this关键字:
继承:
- 父类的私有变量和私有方法是不能被子类继承的。
- 子类的所有的构造方法默认调用的是父类的无参构造,但在子类里面可以通过super指定父类的某个构造方法(必须放在子类构造方法的首行)。
- 构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
- 子类的构造方法默认调用父类的无参构造
-
重载: 在同一类中方法名称相同,方法的参数列表不同
-
重写:子类的访问修饰符必须大于或等于父类的访问修饰符(不能降低访问权限),返回值类型相同或者是父类返回值类型的子类类型,方法名和参数列表相同。
this和super的比较
- this.成员变量 ‐‐ 本类的
- super.成员变量 ‐‐ 父类的
- this.成员方法名() ‐‐ 本类的
- super.成员方法名() ‐‐ 父类的
- this(...) ‐‐ 本类的构造方法
- super(...) ‐‐ 父类的构造方法
public Array(int capacity) {
data = (E[]) new Object[capacity];
//元素个数初始化时默认为0
size = 0;
}
//无参构造函数 容量默认为10
public Array() {
this(10);//调用本类的构造方法
}
关联:(必须先创建huntdog的对象,避免空指针异常)
- 关联和继承都可以实现代码的复用
- 关联的对象可以在成员变量里面,也可以在成员方法及其参数列表里面
创建关联的时候可以在构造方法内创建huntdog的对象。
访问修饰符:
- 对于方法和变量,四种访问修饰符都可以修饰
- 对于类,只能用友好型和公共的修饰
代码块:
- 局部代码块:直接定义在方法内的代码块;
- 初始化代码块:直接定义在类当中,方法外的代码块;初始化代码块本质上放到构造方法当中执行的,因此每次创建对象的时候,都会执行初始化代码块;(相当于构造器)
- 静态代码块:在初始化代码块前面加上一个static ,此代码块称为静态代码块。静态代码块在加载字节码时就会自动调用;
子类和父类的加载顺序:
-
未创建对象前:
- 父类–静态变量
- 父类–静态初始化块
- 子类–静态变量
- 子类–静态初始化块
-
创建对象后:
- 父类–变量
- 父类–初始化块
- 父类–构造器
- 子类–变量
- 子类–初始化块
- 子类–构造器
上传型对象和子类对象调用示意图:
总结:
- 上传型对象直接调用的变量都是父类的变量,方法覆盖后的父类的那些方法名字。
- 子类对象调用的都是覆盖后的变量,方法是覆盖后的全部方法。
- 隐藏方法和继承方法是站在父类的角度,只能调用父类的方法和变量。
- 新增的方法和重写的方法是站在子类的角度,不加super时候,调用的是覆盖后的全部方法和变量,对于被隐藏的变量和方法要用super.的形式去调用。
- 上传型对象的最大好处在于:聚多为一,我们可以用这个“一”去代表“多”,真是运算的时候再向下转型就可以了。
- 强制类型转换是基本数据类型之间的转换,对于引用类型的转换是向上转型和向下转型。
包装类:
- 目的:实现基本数据类型和引用类型的转换;
包装类特有的自动拆箱装箱
package Java后端开发基础.面向对象;
public class day04 {
//整形和字符串举例:
public static void main(String[] args) {
// 自动装箱==>转换成引用类型
Integer a =5;
System.out.println(a);//自动调b用重写后toString()方法
// 自动拆箱==>转换成基本数据类型
int b = new Integer(12);
System.out.println(b);
}
}
注:当直接让包装类参与基本数据运算的时候,不用通过赋值,也可以自动拆箱
与字符串的转换:
public class day04 {
//整形和字符串举例:
public static void main(String[] args) {
//字符串转基本数据类型
String a = "12";
String b = "4";
//通过对应包装类的类方法
int c = Integer.parseInt(a);
//通过包装类的构造器,
int d = new Integer("b");//自动拆箱
//基本数据类型转字符串
//拼接
String e = ""+c;
//string的类方法
String f = String.valueOf(d);
}
}
toString 方法:
-
。对于每一个对象,打印对象的话,会直接调用其toString 方法
-
Object类的toString 方法:
-
Arrays类的toString 方法:(注意:这个toString 是个静态的,且不是重写了object的,是重载)
-
String类的toString 方法:
"==" 与 equals 方法:
- “==”:对于基本数据类型,比较的是值,对于引用类型比较的是地址。
- equals:只适用于引用类型,比较的也是两者之间的值是否相等。
- Object的equals 方法:(比较的就是地址)
- String类重写类equals 方法:(使得string的该方法比较的是字符串的值是否相等)
- 对于不是字符串的,我们可以就可以用 equals 方法来进行判断,但需要将 equals 方法重写。
- 上面这个是按照name idcard age写的,三者相同,就会具有相同的哈希值;当如果只写name和age,那么相同的name'和age就拥有相同的哈希值
单例类:
概念:设计一个类只能创建一个实例,则这个类被称为单例类
创建单例类的步骤:
- 使用 private 关键字修饰构造器。 (不能在其他类里面创建对象)。
- 提供一个 public 的 static 的类方法调用构造器。 (唯一的调用唯一类的方式)。
- 创建一个 static 的成员变量来保存类对象,同时判断对象是否已经创建。
两个设计模式:
总结:创建对象可以在任何地方。
抽象类:
接口:
总结:
- 抽象类继承,如果子类也是一个抽象类,并不要求一定重写父类方法。如果子类不是抽象类,则要求子类一定要实现父类中的抽象方法。
- 接口类继承,如果是一个子接口,可以扩展父接口的方法;如果是一个子抽象类,可以部分或全部实现父接口的方法;如果子类不是抽象类,则要求子类一定要实现父接口中定义的所有方法。
接口和类的继承:
接口的继承与类的继承不一样,接口完全支持多继承,即一个接口可以有多个直接父接口,类是单继承关系,子类只能继承一个父类;对于接口的实现,一个类也可以实现多个接口。
final关键字:
注:对于用final修饰的基本数据类型,赋值后的数值就不能改变了;对于用final修饰的引用类型,它承接的是地址,所以引用类型的值是地址,final修饰后,其地址不会改变,但是,地址里面的东西可以改变(成员变量等等)
System类:(有个计时功能)
封装:成员变量私有话,每个成员变量提供一对公共的get和set方法;
策略模式:
策略模式:导图:
工厂模式:
策略模式和工厂模式结合:
package Java后端开发基础.策略模式和工厂模式;
import java.util.Scanner;
interface Flyable{
void flying();
}
class fly01 implements Flyable{
@Override
public void flying() {
System.out.println("不会飞");
}
}
class fly02 implements Flyable{
@Override
public void flying() {
System.out.println("飞的很高");
}
}
public class Duck {//父类
protected Flyable flyable;//关联,当成员变量
public void showfly(){
flyable.flying();
}
}
class wildDuck extends Duck{
public wildDuck(Flyable flyable) {
this.flyable = flyable;
}
}
class Rhubarbduck extends Duck{
public Rhubarbduck(Flyable flyable) {
this.flyable = flyable;
}
}
class Flyfactory{
public static Flyable fa(String s){
if(s.equals("1")){
return new fly01();
}else{
return new fly02();
}
}
}
class test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
new wildDuck(Flyfactory.fa(scanner.next())).showfly();
new Rhubarbduck(Flyfactory.fa(scanner.next())).showfly();
}
}
非静态内部类:
非静态内部类是当作其外部类的成员变量的,无论是在成员方法里面调用还是main方法里面都必须先new,才可以调用
public class test01 {
private String egg="鸡蛋";
private cook cook = new cook();//把内部类彻底当成成员变量
class cook{
public void cookegg(){
System.out.println("煮鸡蛋");
}
}
public void tes(){
new cook().cookegg();
}
public static void main(String[] args) {
test01 test01 =new test01();
test01.tes();//通过成员方法调用
test01.cook.cookegg();//通过调用成员变量用
test01.new cook().cookegg();//通过new内部类对象调用
}
}
静态内部类:
在外部类里面当作静态变量用的
public class test01 {
private String egg="鸡蛋";
private cook cook = new cook();
static class cook{
public void cookegg(){
System.out.println("煮鸡蛋");
}
}
public void tes(){
new cook().cookegg();
}
public static void main(String[] args) {
test01 tst = new test01();
tst.tes();//通过成员方法调用
tst.cook.cookegg();//通过成员变量调用
test01.cook cook= new test01.cook();
cook.cookegg();//通过静态变量调用
}
}
局部内部类:
匿名内部类:(非抽象子类也可以)
枚举类:
- 定义枚举类时不再使用 class 关键字,而是使用 enum 关键字。
- 主要是为了创建固定个数的对象。