JAVA 面向对象·基础语法3

学过c++的同学肯定都知道PC寄存器,它其实就是指令地址,和汇编语言中的IP寄存器差不多。

PC寄存器:存储JAVA虚拟机正在执行的字节码指令(.class文件)的地址。

JAVA虚拟机栈:存储栈帧

堆:存储GC(垃圾回收器)所管理的各种对象(一个程序中new出来的所有对象)。

方法区:存储每一个类的结构信息(比如构造方法和普通方法)。

this:是一个指向当前对象的引用。

*********this的本质是一个隐藏的 位置最靠前的方法参数。(隐藏参数)

*********只能在构造方法中使用this去引用其他构造方法。

包的本质其实就是文件夹。

在JAVA中,任何新建的类都会默认为继承JAVA的基类—Object(它的包名为 Java.lang.object)。

子类的构造方法必须先调用父类的构造方法,在执行后面的代码。

方法签名=方法名+参数类型

重写与重载——Super

在JAVA 中,重写需要注意以下几个方面:

1.子类的返回类型一定要小于或等于父类的的返回类型

Super:访问父类中定义的成员变量,可以调用父类中定义的方法(包括构造方法)。

******************JAVA 的硬性规定:子类的构造方法必须先调用父类的构造方法,再执行后面的代码。

Java中的覆盖指的是实例方法。

封装

1.成员变量private化,提供public的setter,getter

Static类

1.被static修饰:成员变量,类变量,静态变量,静态字段

(在程序运行的过程中,只占用一份固定的内存,一般存储在方法区)

2.没有被static修饰:实例变量

(每个实例内部都有一份内存,存储在堆空间)

3.被static修饰的方法:类方法,静态方法

—方法内部是不可以使用this关键字的

—可以直接访问类变量,类方法

—不可以直接使用实例变量,实例方法

—可以通过实例,类访问

4.没有被static修饰的方法:实例方法(只能通过实例调用,不能通过类名调用)

*************(实例内部必有this)

初始化块·静态初始化块

每创建一次实例时,初始化块就会去执行一次,而静态初始化块与实例是不挂钩的

*******************手动为实例变量赋上初始值:

1.在声明中

2.在构造方法中

3.在初始化块中

public class Person{
     public int age;
     //初始化块
     {
         age = 10;
     }
}

//编译器会将初始化块复制到每个构造方法的头部(每创建一个实例对象,就会执行一次代码块)

*******************手动为类变量赋上初始值:

1.在声名中

2.在静态初始化块中

public class Person{
    public static int count;
    //静态初始化块
    static{
        count = 10;
    }
}

//当一个类被第一次主动使用时,JVM会自动对类进行初始化

//当一个类被进行初始化时会执行静态初始代码块

image-20220502165901805

以上代码运行结果如图

一段代码中可以有多个初始化块和静态初始化块,按照在源码中出现的顺序被执行

单例模式

构造一个单例模式(饿汉式单例模式):

public class Rocket{
    //私有的静态的实例变量
    private static Rocket instance = new Rocket();
    //首先不能让外界访问你的构造方法,即构造方法私有化(就不能随便去创建对象)
    private Rocket() {
    //其次 提供一个公共的静态的方法,返回唯一的那个实例
        public static Rocket getInstance(){
            return instance;
        }
    }
}

构造一个单例模式(懒汉式单例模式):

public class Rocket{
	private static Rocket instance = null;
	private Rocket() {
		if(instance==null){
			instance = new Rocket();
		}
		return instance;
	}
}

//有线程安全问题

Final类

子类对象的内部不仅有自己的成员变量,还有父类的所有成员变量。

被final修饰的类:不能被继承。

被final修饰的方法:不能被重写。

被final修饰的变量:只能进行1次赋值。

凡是static final修饰的变量都采用大写字母,若有多个单词中间需用下划线连接。

被static final修饰的可以看作一个常量。//也叫做编译时常量(compile—time constant)。

image-20220503195544943

//宏替换:

1.预处理:主要任务包括删除注释、插入被#include进来的文件内容、定义和替换由#define 定义的符号以及确定代码部分内容是否根据条件编译(#if )来进行编译。

2.宏定义:⑴宏常量:用#define来定义一个符号常量

​ ⑵宏语句:定义一条或多条语句

​ ⑶宏函数:用宏来定义函数,因为宏定义也可以带参数

​ ⑷其他:#undef 是用来撤销宏定义的

静态导入

用一段代码实现静态导入:

import static com.mj.other.Test.*;

经典使用场景:圆周率PI的使用。

import static java.lang.Math.PI;
//import static java.lang.Math.*;
public class Main{
    public static void main(String args[]){
        //max(a,b);
        System.out.println(" 2 * PI * 10");
    }
}

但是过度使用静态导入,会产生歧义,让读者不明白这些到底是在哪个类中定义的。

嵌套类 Nested Class

嵌套类:定义在另一个类中的类,分为静态嵌套类(被static修饰)和非静态嵌套类(没有static修饰)。//***非静态嵌套类也叫内部类

外部类:在嵌套类外层的类。

顶级类:最外层的外部类。

内部类:跟实例变量,实例方法一样,内部类与外部类的实例相关联。

​ 必须先创建外部类实例,在调用外部类实例去创建内部类实例。(记得导包)

​ 如下图 内部类不可以定义任何static成员。(除非是编译时常量——即被static final修饰)

image-20220504171451999

​ 内部类可以直接访问外部类中的所有成员,即使该成员被声名为private。

​ 外部类可以直接访问内部类的任何成员变量和方法,即使该成员被声名为private。

package www;
//内部类举例(公司名字,公司解雇,员工名字,序号,显示员工信息)
public class Company {
	private String name;
	public Company(String name) {
		this.name =name;
	}
	public void Fire(Employee e) {
		System.out.println(name+"fire"+e.number);
	}
	public class Employee{
		private int number;
		public Employee(int number) {
			this.number = number;
		}
		public void show() {
			System.out.println(name+":"+number);
		}
	}
}

内部类细节:当外部类和内部类中都出现了相同的变量名,若想在内部类中调用外部类的那个变量,应表示为:

public class OuterClass{
    private int x = 1;
	class InnerClass{
		private int x = 2;
		System.out.println(OterClass.this.x);
	}
}

静态嵌套类 Static Nested Class

静态嵌套类:在行为上相当于顶级类,只是定义的代码写到了另一个类中。(可以理解为:借另一个类的的空间去放一下代码)

(与一般顶级类相比)静态嵌套类的特殊权限:可以直接访问外部类里除了实例变量和实例方法的其他成员,即使该成员被声名为private。

*************若静态嵌套类想要访问外部类中的实例变量和实例方法,则必须先要new一个对象,通过对象调用实例变量和方法。

什么情况下使用嵌套类?

1.如果类A只用在类C内部,可以考虑将类A嵌套在类C内部。

2.封装性更好,程序包更加简化

3.增强可读性,维护性

4.如果类A经常访问类C中的非公共成员,可以考虑将类A嵌套在类C内部。

5.也可以根据需要将类A隐藏起来,不对外暴露

6.如果类A要经常访问类C中的非公共的实例成员,则设计成内部嵌套类,否则设计为静态嵌套类。

7.如果只有实例A才能创建实例C,那么可以把C作为A的一个内部类来使用

局部类 Local Class

局部类:定义在代码块中的类(可定义在方法中,for循环中,if语句中)。

1.局部类不能定义除了编译时常量以外的任何static成员

2.局部类只能访问 final类或者 有效final类 (只进行一次赋值)的局部变量

3.从Java 8 开始,凡是没有进行第二次赋值的局部变量就被称为 有效final 。

4.局部类可以直接访问外部类中的所有成员,即使该成员被声名为private。

5.局部类只有定义在实例相关的代码块中,才能直接访问外部类中的实例成员(实例变量,方法)

抽象类

1.抽象方法

抽象方法:被abstract修饰的方法。

注意事项:1.只有方法声明,没有方法实现(参数列表后没有大括号,而是分号)

​ 2.不能是private权限(因为定义抽象方法的目的是让子类去实现)

​ 3.*************只能是实例方法,不能是类方法

​ 4.只能定义在抽象类和接口中

抽象类:

1.是为了给别人继承的,所以不能使用final 修饰,也不能实例化,子类必须实现抽象父类中的所有的构造方法

**********************抽象类不能创建实例对象

2.抽象类其实可以理解为在原来的普通类基础上增加了一个新的功能——构造抽象方法

接口 Interface

API:应用编程接口,提供给开发者一组调用的功能。

而Java中的接口,是一系列方法声明的集合。(抽象方法)

implements 是类使用接口时的关键字。

接口可以定义抽象方法,常量,嵌套类型,默认方法,静态方法

上述可以定义的内容都含有隐式public,所以在写此段代码时可以省略不写

接口中的常量可以省去static final ,接口中是不能出现成员变量的。

接口中不能自定义构造方法,不能实例化,不能定义(静态)代码块。

接口名称可以在任何使用类型的地方使用,可以理解为接口也是一种类型。如果一个类实现的多个接口中有相同的抽象方法,那么只需要实现此方法一次。

接口一般是放一些行为,能力的代码块,而继承是代表你属于哪一类

在接口里写的方法都是抽象方法.

抽象类与接口的对比

抽象类

1.继承:

class  A  extendS  D{}//A是D

2.何时选择抽象类?

⑴在紧密相关的类之间共享代码

⑵除public以外的访问权限

⑶需要创建实例变量和非final类的静态变量

接口:

1.实现:

A  implements  D{              //A会D中的所有行为
    
}

2.何时选择接口?

⑴不相关的类实现相同的方法

⑵只是定义行为,不关心是谁具体实现了这个行为

⑶想实现类型的多重继承

接口的升级问题

默认方法

1.用default修饰默认方法,并且此方法能够具体实现

2.默认方法只能是实例方法

3.重新声明默认方法,将默认方法声明为抽象方法(此类必须是抽象类)

4.如果父类的非抽象方法与接口的默认方法相同时,最终调用父类的方法

5.可以通过super关键字来调用接口的默认方法(……忘了……{{{(>_<)}}})

静态方法

1.接口中的定义的静态方法只能通过接口名调用,不能被继承

使用接口的好处

客户端→服务器→业务解析→业务层→DAO层

1.业务层调用DAO层 最好通过接口去调用。

2.涉及到了一些架构相关的问题,具体内容会在第二、三部分进行讲解。

多态

多态:具有多种形态。(开发中经常会用到接口,也可以叫做 面向接口编程)

体现:

1.父类(接口)类型指向子类对象

2.调用子类重写的方法

虚方法调用:JVM会根据引用变量指向的具体对象来调用相应的方法。(相当于c++虚函数调用)

Instanceof : 可以通过instanceof来判断某个类型是否属于某种类型。(非常常用

父类类型指向子类对象,这个顺序是绝对不能颠倒的。

((Dog)Animal).wang();//强制转换,将animal类转化为Dog类
Dog dog1 = new Dog();
dog1.run();   //Dog-run

Animal dog2 = new Dog();
dog2.run();   //Animal-run

以上属于类方法(静态方法)调用,类方法是不看具体的实例对象的,只看对象属于哪一类。

成员变量的访问细节:

和类方法调用相似,在访问成员变量之前,也只会看对象属于所在的类,根据就近原则来进行下一步操作。

所以这样会为程序带来歧义,最好是将类中的public权限变成private。

匿名类(常用)

当接口,抽象类的实现类,只在项目中出现过一次,可以考虑使用匿名类.

public class Main{
   public static void main(String args[]){
			Runnable person = new  Runnable() {          //匿名类
				
				@Override
				public void run() {
					// TODO Auto-generated method stub
					System.out.println("person-run");
				}
			};
			person.run();
	
   }
}  			

匿名类不能定义除编译时常量以外的任何static成员.

匿名类不可以定义构造方法。

匿名类其实和局部类十分相似,只能访问final或者 有效final的局部变量.

举个例子(如下图)

public interface Eatable {
      String name() ;    //相当于抽象方法,所以格式不能出错
      int enery() ;
}

public class Person  {
	public void eat(Eatable e) {
		System.out.println("person-"+e.name()+"-"+e.enery());
	}
}
public static void main(String args[]){
			Person person = new Person();
			person.eat(new Eatable() {
				
				@Override
				public String name() {
					return "apple";
				}
				
				@Override
				public int enery() {
					return 50;
				}
			});
   }
}  			                                        //person-apple-50
或
public static void main(String args[]){
			Person person = new Person();
			Eatable beef = new Eatable() {
				
				@Override
				public String name() {
					// TODO Auto-generated method stub
					return "beef";
				}
				
				@Override
				public int enery() {
					// TODO Auto-generated method stub
					return 500;
				}
			};
			person.eat(beef);
}  			
}                                                //person-beef-500

匿名类的常见用途

1.代码传递:可以节省很多空间,不需要再去创建一个新的类。

举个例子,测试一段代码所用的时间


2.过滤器

3.回调:callback,其实与代码传递相类似。

匿名类的排序

1.java的自动排序(升序)

Arrays.sort(a);

2.Java的倒序排序

Arrays.sort(a,new comparator<Integer>()){
	@Override
	public int compare(Integer o1, Integer o2){   //这里不能直接写int,不然就会报错
		return o2-o1;
	}
});

原理如下:

image-20220515162125205

3.打印数组

System.out.println(Arrays.toString(a));//括号中填数组名

Lambda Expression

1.函数式接口:只包含一个抽象方法的接口。

可以在上面加上一个注解,表明它是一个函数式接口。

@FunctionalInterface
public interface Testable{
	void test(int b);
}

当匿名类实现的是函数式接口时,可以使用Lambda进行简化。(相当于是用Lambda替换掉匿名类)

Lambda 的使用格式:

(参数列表) -> {

	return XXXX;
}

image-20220515172642493

Lambda的使用注意:

1.Lambda只能访问final或者有效final的局部变量。

2.Lambda没有引入新的作用域

匿名类与Lambda的对比

1.在作用域方面是有所区别的

方法引用

1.引用类方法

image-20220515193345183

类名::方法名

2.引用特定对象的实例方法

system.out.println 的本质就是引用特定对象的实例方法。

也可以简化为 具体的对象::调用的方法名

3.引用特定类型的任意对象的实例方法

image-20220515200938097

本来字符串底层就有compare方法,调用它可以比较大小

image-20220515201135621

忽略大小写进行比较

也可以将上述代码简化成下面这种形式

image-20220515201719880

所以引用特定类型的任意对象的实例方法是 类名::方法名

4.引用构造方法

image-20220516094124088

所以引用构造方法的格式为 类名::new

5.引用数组的构造方法

格式为 int[ ] :: new ;

6.引用当前类中定义的实例方法

格式为 this::方法名

7.引用父类中定义的实例方法

格式为 super::方法名

方法引用的最后总结:

image-20220515201921286

posted @ 2022-05-16 11:16  xiaobailing  阅读(50)  评论(0)    收藏  举报