Java学习笔记12.——面向对象进阶
这节需要讲的是有
static
继承
多态
抽象
接口
内部类
文章目录
前言
对于static的疑问来源于为什么不能访问非静态的成员变量和方法,this关键字是当初的开发者没有设置,因为static代表是公用使用的,在堆区中有一个静态存储空间。
一、static 静态的
static:表示静态,是Java中的一个修饰符,可以修饰成员方法,成员变量。
这里是用一个实例来引入的,我记忆也很深刻。
先做一个student,javabean类,其中有姓名,年龄,性别属性,和学习行动。
package a01StaticDemo2;
public class Student {
private String name;
private int age;
private String sex;
public Student(){}
public Student(String name,int age,String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age = age;
}
public String getSex(){
return sex;
}
public void setSex(){
this.sex = sex;
}
public void study(){
System.out.println(name+"正在学习");
}
public void show(){
System.out.println(name+","+age+","+sex);
}
}
在Test测试类中,可以生成多个student对象。假如现在加入班主任属性,那就会出现一个情况。
修改如下
Test类中使用
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三",12,"女");
s1.teacherName = "张老师";
s1.study();
s1.show();
Student s2 = new Student("李四",13,"女");
s2.show();
}
}
依据道理来说,一个班只有一个辅导员。
如果是如上诉的运行结果来看,这显然是不合理的,所以这时候就可以使用static静态修饰符。
public class Test {
public static void main(String[] args) {
Student s1 = new Student("张三",12,"女");
//Student.teacherName = "张老师";
s1.teacherName= "张老师";
s1.study();
s1.show();
Student s2 = new Student("李四",13,"女");
s2.show();
}
}
调用方式:
- 类名调用(推荐,因为毕竟静态变量属于类,而不属于对象)
- 对象名调用
运行结果如下,现在就是同一个老师。
1.运行内存
知识回顾,栈区存放是正在运行的方法,堆区是存放引用型数据类型。
所以Test方法中,main方法进栈之后,
- student字节码文件进入方法区
- 创建学生对象s1
- 堆区中创建了学生对象,把学生对象地址值赋值给s1
- 在堆区中的==静态存储位置(静态区)==中创建静态成员变量teacherName,把张老师的值覆盖null
- s1使用study()方法进栈,然后打印出正在学习,然后出栈
- s1调用show()方法进栈,然后调用了静态成员变量,打印完之后出栈
- 创建了第二个学生对象,在堆区中然后赋值,把地址值传过去。
- s2掉用show()方法进栈,会使用到静态区中的teacherName成员变量然后打印完出栈
- main方法中运行完了,然后也出栈
- 堆内存中没有指向它的指针,也就被回收了。
1.总结
静态变量是随着类的加载而加载的,优先与对象出现的。原因如下:
百度如下:
1.静态变量是在类加载时初始化的,而不是在对象创建时初始化的。这是因为在Java中,类的加载是一个独立的过程,发生在对象创建之前。
2.类加载是JVM(Java虚拟机)的一项重要工作,它负责将类的字节码转换为可执行的Java代码。在类加载过程中,JVM会首先加载类的静态变量,因为它们被声明为static。这些静态变量包括静态变量、静态代码块和静态方法。
3.静态变量是类级别的变量,它们不属于任何一个特定的对象,而是与类本身相关联。因此,当类被加载时,静态变量就会被初始化。这个过程通常在任何对象被创建之前发生。
4.在类加载过程中,JVM会首先执行静态变量和静态代码块。这意味着在任何对象被创建之前,静态变量就已经被初始化了。这样做是为了确保静态变量在使用之前已经有了初始值。
5.总之,静态变量是在类加载时初始化的,而不是在对象创建时初始化的。这是由于类加载是一个独立的过程,发生在对象创建之前。静态变量是类级别的变量,它们与类本身相关联,而不是与特定的对象相关联。因此,在类加载时初始化静态变量可以确保它们在使用之前已经有了初始值。
1.静态变量
特点:
- 被该类所有对象共享,只要公共使用的就可以用static修饰。
- 不属于对象,属于类。
- 随着类的加载而加载
2.静态方法
特点:
- 多用在测试类和工具类中,(比如Math工具类)
- Javabean类中很少用,除非设计模式
上面两种调用方式:
- 类名调用(推荐)
- 对象名调用
Javabean类 | 用例描述一类事物的类。比如student,Teacher,Dog,Cat等。 |
---|---|
测试类 | 用例检查其他类是否书写正确,带有mian方法的类,是程序的入口 |
工具类 | 不是用来描述一类事物的,而是帮我们做一些事情的类 |
3.工具类实例
1.定义数组工具类
定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
提供一个工具类方法printArr,用于返回整数数组的内容。
- 返回的字符串格式如 : [ 10,20,50,34,100 ] (只考虑整数数组,且只考虑一维数组)
提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组
package a02StaticDemo3;
import java.util.StringJoiner;
public class ArrayUtil {
// 定义一个测试类TestDemo,调用该工具类的工具方法,并返回结果。
//提供一个工具类方法printArr,用于返回整数数组的内容。
// 返回的字符串格式如:[10,20,50,34,100](只考虑整数数组,且只考虑一维数组)
public static String printArr(int[] arr){
StringBuilder sb = new StringBuilder();
StringJoiner sj = new StringJoiner(",","[","]");
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i!= arr.length-1){
sb.append(arr[i]).append(",");
}else {
sb.append(arr[i]);
}
}
sb.append("]");
return sb.toString();
}
//提供这样一个工具方法getAerage,用于返回平均分。(只考虑浮点型数组,且只考虑一维数组
public static double getAerage(int[] arr){
double sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
double average = sum/arr.length;
return average;
}
}
测试类
package a02StaticDemo3;
public class TestDemo {
public static void main(String[] args) {
int[] i = {1,2,3,4,5};
ArrayUtil.printArr(i);
System.out.println(ArrayUtil.getAerage(i));
}
}
2.定义学生工具类
工具类需求:
需求:定义一个集合,用于存储3个学生对象。学生类的属性为:name、age、gender
定义一个工具类,用于获取集合中最大学生的年龄。
package a02StaticDemo3.student;
import java.util.ArrayList;
public class StudentUtil {
private StudentUtil(){}
public static int getAge(ArrayList<Student> list){
int maxAge = 0;
for (int i = 0; i < list.size(); i++) {
int age = list.get(i).getAge();
if (age > maxAge){
maxAge = age;
}
}
return maxAge;
}
}
测试类
package a02StaticDemo3.student;
import java.util.ArrayList;
public class StudentTest {
public static void main(String[] args) {
Student s1 = new Student("张三",12,"男");
Student s2 = new Student("李四",16,"男");
Student s3 = new Student("王麻子",10,"男");
ArrayList<Student> list = new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
System.out.println(StudentUtil.getAge(list));
}
}
4.static的注意事项
this:表示当前方法调用者的地址值
这个this:是由虚拟机赋值的
注意事项:
- 静态方法只能访问静态变量和静态方法
- 不是静态方法可以访问非静态方法和静态方法和非静态变量和静态变量
- 静态方法中没有this关键字
因为静态方法变量都是公共使用的,所有就没有设置this关键字的功能。
1.代码理解
这段代码是第一个例子里面的,我在study()方法中使用this关键字调用show()方法,和不使用this关键字调用study()方法是一样的,说明this关键字在很多地方都是隐藏了的。
比如:
public void stydy(Student this){
this.show();
}
这些都是隐藏的this,实际上去掉this就是平常使用的状态。
如果把study()方法加上static静态修饰符,则会报错,就算删掉this也是会报错的,就比如name。
这证明了静态方法中不能有非静态成员变量和非静态方法。
但是非静态方法可以访问静态方法和静态成员变量(第一个例子中的班主任老师名字就是静态成员变量)
静态的属于类,非静态属于对象!
2.内存理解
首先,jdk8以后静态存储位置(静态区)不在方法区,在堆内存里面。
public class Student{
String name;
static String teacherName;
public static void method(){
System.out.println(name + "..."+ teacherName);
}
public void show(){
System.out.println(name+"..."+ teacherName);
}
}
public class TestStatic(){
public static void main(String[] args){
Student.teacherName = "阿维老师";
Student.method();
}
}
main方法是程序的唯一入口,所以main方法先进栈内存,
执行第一行代码,Student.teacherName = “阿维老师”;
这里加载Student字节码文件进方法区,堆内存区中创建静态成员变量,其值为null,然后被赋值为"阿维老师"。
执行第二行代码,静态method方法进入栈内存,在main方法上面。method方法中打印name和teacherName.静态方法能访问静态方法,所以teacherNmae能访问,但是name是非静态成员变量,前面默认this关键字,需要有调用者调用,此时连对象都没有,故而name是不能被调用的。
并且非静态的只能由对象调用,静态没有this掉用不了这些。
就算
3.main方法
public class Test{
public static void main(String[] args){
System.out.println("Hello World");
}
}
其中
public是公共修饰符——被JVM调用,访问权限足够大
static 静态修饰符——被JVM调用,不用创建对象直接类名访问因为main方法是静态的,所以测试类中其他方法也 是需要静态的
void 返回值为空——被JVM调用,不需要给JVM调用
mian 不是关键字——一个通用的名称,不是关键字,但是被JVM识别
String[] args——数组,以前用于接收键盘录入数据的,现在没用。
args不是通过控制台来录入数据的,idea中是在这里面
** 因为idea版本和老师不一样,所以这个图片是老师的**
总结
因为这段时间的一些波动,所以导致static静态知识学的周期就变长了,知识性了解得就不是特别深。
static是静态的,只能访问静态的成员变量和方法
非静态的能访问非静态的成员变量和方法以及静态的成员变量和方法
main方法是程序的主入口,不是关键字,static静态修饰,所使用的方法也都是需要静态的(这里解决了我前面的疑问)
static不能访问非静态的原因是它是随着类的加载而加载,对象是类加载之后的在堆区中创建的,先后顺序不一且static是公共使用的,所以没有this关键字。
由于this关键字是当前调用者访问的地址的原则(这个this是由虚拟机赋值的),static不能调用非静态的成员变量和方法,只能由对象调用这些。
如果有人看见,发现有错误的地方还请指正一下。