JavaSE | 05-面向对象进阶

static(静态)

静态变量

在JavaBean中,不加static只能供一个对象使用

  • 被 static 修饰的变量属于类,所有实例共享同一个变量值
  • 在内存中只存在一份,当类被加载时初始化
  • 通常用于表示所有对象共有的属性
public class Student {
    // 静态变量(类变量)
    public static String schoolName = "阳光中学";
    // 实例变量
    private String name;
    
    public Student(String name) {
        this.name = name;
    }
    
    public static void main(String[] args) {
        // 直接通过类名访问静态变量
        System.out.println(Student.schoolName); // 输出:阳光中学
        
        Student s1 = new Student("张三");
        Student s2 = new Student("李四");
        
        // 也可以通过实例访问(不推荐)
        System.out.println(s1.schoolName); // 输出:阳光中学
        
        // 修改静态变量,所有实例都会受到影响
        Student.schoolName = "星光中学";
        System.out.println(s2.schoolName); // 输出:星光中学
    }
}	

[!NOTE] JDK8之前,静态区处于方法区里面。 JDK7之后,静态区处于堆空间之中。

静态方法

  • 多用在测试类和工具类当中
  • JavaBean中很少用

[!NOTE] JavaBean类:用来描述一类事物的类 测试类:用来检查其他类是否书写正确,带有main方法的类,是程序的入口 工具类:不是用来描述一类事物的,而是帮我们做一些事情的类

工具类

1.类名见名知意 2.私有化构造方法

    public class ArrUtil{
        private ArrUtil(){}
    }
private ArrayUtil() {} 是一个私有构造方法
由于构造方法被声明为 private(私有),这意味着在类的外部无法调		用这个构造方法,也就无法创建 ArrayUtil 类的对象实例。

防止这个工具类被意外地实例化

[!NOTE] 如果不写这个私有构造方法,Java 会默认提供一个公共的无参构造方法 这样别人就可能误将其当作普通 JavaBean,写出new ArrayUtil()这样的代码(虽然创建了对象也没用,但不符合设计意图)

3.方法定义/为静态


static的注意事项

  • 静态方法只能访问静态变量和静态方法
  • 非静态方法可以访问静态变量或静态方法,也可以访问非静态的成员变量和非静态的成员方法
  • 静态方法中没有this关键字
public class Student{
	String name;
	int age;
	static String teachername;
	
	//this:表示当前方法调用者的地址值
	//这个this:是由虚拟机赋值的
	public void show1(Student this){//此处的this是虚拟机暗加的
		sout("this:" + this);//地址值
		sout(name+","+age+","+teachername);
		//实际上是this.name和this.age和this.teachername
		
		show2();
		//实际上是this.show2();
		//意思是当前show1调用的对象继续调用show2
		
	}
	
	public void show2(){}
	poublic static void method(){//此处的静态方法却不会有this关键字
		//不可调用非静态的成员变量和成员方法
		sout("静态方法");
	}
	

}

public class StudentTest(){		
	public static void main(String[] args){
		Student.teachername  = "老师姓名";
		
		Student s1 = new Student();
		sout("s1:" + s1);//地址值
		s1.name = "张三";
		s1.age = 23;
		s1.show1(); //此处的s1对应this
		
		Student s2 = new Stduent();
        sout("s2:" + s2);//地址值
		s2.name = "李四";
		s2.age = 24;
		s2.show1();//此处的s2对应this
		
	}
}

打印后,s1与this的地址值相同,s2与this的地址相同。

内存的加载

静态:随着类的加载而加载
非静态:与对象有关

main方法

	public class HelloWorld{
		public static void main(String[] args){
			//[]:数组
			//String:数据类型
			//args:数组名
			sout("HelloWorld");
		}
	}
  • public:被JVM调用,访问权限足够大
  • static:被JVM调用,不用创建对象,直接类名访问。
  • 因为main方法是静态的,所以测试类中的其他方法也需要是静态的
  • void:被JVM调用,不需要给JVM返回值
  • main:一个通用的名称,不是关键字,但是被JVM识别
  • String[] args:以前用于接受键盘录入数据,现在没用

继承

  • Java中提供一个关键字extends,用这个关键字,我们可以让一个类和另一个类建立起 继承关系
    public class Student extends Person{}
  • Studet成为子类(派生类),Person称为父类(基类或超类)。 使用继承的好处:
    • 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性
    • 子类可以在父类的基础上,增加其他的功能,使子类更强大。

?什么时候用继承: 当类与类之间,存在相同(共性)的内容,并满足子类是父类的一种,就可以考虑用继承,来优化代码。


继承特点

Java只支持单继承,不支持多继承,但支持多层继承。

  • 单继承:一个子类只能继承一个父类
  • 不支持多继承:子类不能继承多个父类

[!NOTE] 每一个类都直接或间接继承于Object

[!WARNING]

  1. 构造方法不可被继承
  2. 成员变量私有和非私有都能被继承(私有不可直接使用)
  3. 成员方法只有非私有非static非final(能被加入虚方法表)能被继承

在继承中 成员变量的访问特点

就近原则

public class Fu{
	String name = "Fu";
}
public class Zi extends Fu{
	String name = "Zi";//若没有此语句会打印Fu
	public void ziShow(){		
		String name = "ziShow";//若没有此语句会打印Zi
		sout(name); //ziShow...依次向上找name
	}
}
public class Fu{
	String name = "Fu";
}
public class Zi extends Fu{
	String name = "Zi";
	public void ziShow(){		
		String name = "ziShow";
		//局部->本类->父类
		sout(name); //ziShow
		sout(this.name);//Zi
		//this:本类
		sout(super.name);//Fu
		//super:父类
        }
}

[!IMPORTANT] name:从局部位置开始往上找… 局部 –> 本类 –> 父类 this.name:从本类成员位置开始往上找… 本类 –> 父类 super.name:从父类成员位置开始往上找…父类

在继承中成员方法的访问特点

直接调用满足就近原则,super调用直接访问父类 方法的重写: 当父类的方法不能满足子类现在的需求时,需要进行方法重写

书写格式: 在继承体系中,子类出现了和父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。 @Override重写注解 @Override是放在重写后的方法上,校验子类重写时语法是否正确。

方法重写的本质

A类——-继承——>B类—继承—>C类

子类覆盖了从父类继承下来的虚方法表里的方法

写入方法A(method2)B(method2)C(method1,method2)
虚方法表C:method1C:method1C:method1
A:method2()重写B:method2(重写)C:method2

[!NOTE] 1.重写方法的名称、形参列表必须与父类中的一致 2.子类重写父方法时.,访问权限子类必须大于等于父类(空 < protected < public) 3.子类重写父类方法时,返回值类型必须小于等于父类 4.重写的方法尽量和父类保持一致 5.只有被添加到虚方法表中的方法才能被重写


在继承中构造方法的访问特点

  • 父类中的构造方法不会被子类继承,但是可以使用super调用。
  • 子类中所有的构造方法默认先访问父类中的无参构造,在执行自己。(子类构造方法第一句默认是super(),不写也存在,若想调用父类有参构造,则必须使用super)
  • 如果想要访问父类的有参构造,必须手动书写

this 与 super

this:理解为一个变量,表示当前方法调用者的地址值。 super:代表父类存储空间。

关键字访问成员变量访问成员方法访问构造方法
thisthis.成员变量—访问本类成员变量this.成员方法—访问本类成员方法this(…)—访问本类构造方法
supersuper.成员变量—访问父类成员变量super.成员方法—访问父类成员方法super(…)—访问父类构造方法

this():

[!NOTE] 在子类中可以直接快捷使用构造函数

class Student{
    String name;
    int age;
    String school;
    Student(){
    	//表示调用本类的其他构造方法
    	//虚拟机不会再添加super();
        this(null,0,"默认大学");
    }

    public Student(String name, int age, String school) {
    	//因为调用之后此处有一个super();
        this.name = name;
        this.age = age;
        this.school = school;
    }
}

多态

同类型的对象,表现出不同的形态 表现形式:父类类型 对象名称 = 子类对象; 前提: 1.有继承/实现关系
2.有父类引用指向子类对象
3.有方法重写

好处:使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利。

public class Test {
    public static void main(String[] args) {
        Student s = new Student("张三",18);
        Teacher t = new Teacher("王建国",22);
        Admin a = new Admin("管理员",20);

        register(s);
        register(t);
        register(a);
    }
    //接收老师,学生,管理员
    public static void register(Person p){
    	//在每一个子类中都重写了show方法
    	//p.show(),会直接指向子类的方法
        p.show();
    }
}

多态调用成员变量的特点

`父类类型 对象名称 = 子类对象;`
  • 变量调用:编译看左边,运行也看左边
	//Animal 默认name为"动物"
	//Dog 默认name为"狗"
	Animal a = new Dog();
	//编译看左边:Javac编译代码的时候,会看左边的父类有没有这个变量,如果有,编译成功,反之失败
	//运行也看左边:Java运行代码的时候,实际获取的就是左边父类中成员变量的值
	sout(a.name);//动物
  • 方法调用:编译看左边,运行看右边
	Animal a = new Dog();
	//编译看左边:Javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,反之失败
	//运行看右边:Java运行代码的时候,实际上运行的是子类中的方法
	a.show();//Dog---show方法

[!NOTE] 成员变量:在子类的对象中,会把父类的成员变量也继承下来。父:name,子:name(本质上时在内存中开辟了一个地址空间存储两个name) 成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类的方法进行覆盖。

优点:使用父类型作为参数,可以接收所有子类对象
弊端:不能调用子类的特有功能(方法),但是可以通过强制转换解决

	Animal a = new Dog();
	Dog d = (Dog)a;//大范围 -> 小范围	
	
	//判断对象是不是某一个类中的 instanceof
	if(a instanceof Dog){
		Dog d = (Dog)a;
		d.lookHome();
	}else if{
		Cat c = (Dog)a;
		c.catchMouse();
	}else{
		sout("没有这个类型,无法转换");
	}
	
	//新特性
	if(a instanceof Dog d){
//		Dog d = (Dog)a;
		d.lookHome();
	}else if(a instanceof Cat c){
//		Cat c = (Dog)a;
		c.catchMouse();
	}else{
		sout("没有这个类型,无法转换");
	}

包就是文件夹,用来管理不同类的Java类,方便后期代码维护 包名一般都用小写 使用其他类的规则: 1.使用同一个包中的类时,不需要导包
2.使用Java.lang包中的类时,不需要导包
3.其他情况都需要导报
4.如果同时使用两个包的同名类,需要用 全类名

全类名:包名 + 类名


final

方法:表明该方法时最终方法,不能被重写
类:表明该类是最终类,不能被继承
变量:叫做常量,只能被赋值一次 (c/c++中的const)

[!TIP] 常量的命名规范 单个单词:全部大写 多个单词:全部大写,单词之间用下划线隔开

[!NOTE] final修饰的变量是基本类型:那么变量存储的数据值不能发生改变
final修饰的变量是引用类型:那么变量存储的地址值不能发生改变,对象内部的可以改变(静态指针)

	//记录的地址值不能发生改变
	final Student S = new Student("张三",23);
	//	S = new Student(); !报错
	S.setName("李四"); // 对象内部可以改变

补充:字符串不可变的原因是String是由final和private存储的数组


权限修饰符

  • 控制一个成员能够被访问的范围
  • 可以修饰成员变量,方法,构造方法,内部类。
修饰符同一个类中同一个包中其他类不同包下的子类不同包下的无关类
private
空着不写(默认)
protected
public

代码块

构造代码块:从多个构造方法中抽取重复代码,而且会先于构造方法的执行

静态代码块

格式:static{} 特点:需要static关键字修饰,随着类的加载而加载,并且自动触发,只执行一次。

	static{
		sout("执行静态代码块");
		//随着类的加载而加载,并且只执行一次。
	}

应用:数据初始化

    //sattic里面只能用static
	static ArrayList<Student>list = new ArrayList<>();
	static{
		sout("初始化");
	}
	
	public staic void main(String[] args){
		...
	}

抽象类和抽象方法

抽象类: 是一种不能被实例化的类,它主要用于定义其他类(子类)的共同接口和部分实现.

  • 抽象方法一定在抽象类中
  • 抽象类不一定含有抽象方法.

抽象类的主要特点: 1.不能实例化:抽象类本身不能创建对象,只能作为父类被继承
2.可以包含抽象方法:抽象方法只有声明,没有具体实现,必须由子类实现
3.可以包含具体方法:抽象类也可以有已实现的方法,供子类直接使用或重写
4.子类必须实现所有抽象方法:如果子类没有实现父类的所有抽象方法,那么子类也必须是抽象类

接口

  • 接口用关键字**interface**来定义
    public interface 接口名{}
  • 接口不能实例化
  • 接口和类之间是实现关系,通过**implements**关键字表示
    public class 类名 implement 接口名{}
  • 接口的子类(实现类) 要么重写接口中的所有抽象方法 要么是抽象类

[!NOTE] 1.接口和类的实现关系,可以单实现,也可以多实现public class 类名 implements 接口名1,接口名2{} 2.实现类还可以在继承一个类的同时实现多个接口。 public class 类名 extends 父类 inplements 接口名1,接口名2{}

成员特点和接口中的各种关系

接口中成员的特点

  • 成员变量

    只能是常量 默认修饰符:public static final

  • 构造方法:没有

  • 成员方法 只能是抽象方法 默认修饰符:public abstract

  • JDK7以前:接口中只能定义抽象方法

  • JDK8的新特性:接口中可以定义有方法体的方法

  • JDK9的新特性:接口中可以定义私有方法

接口和类的关系

  • 类和类的关系

继承关系,只能单继承,不能多继承,但是可以多层继承

  • 类和接口的关系

实现关系,可以单实现,也可以多实现,还可以在继承一个类同时实现多个接口

  • 接口和接口的关系

继承关系,可以单继承,也可以多继承

接口中的默认方法

格式: public default 返回值类型 方法名(参数列表){ }

接口中默认方法的注意事项

1.默认方法不是抽象方法,所以不强制被重写。但是如果被重写,重写的时候去掉default关键字
2.public可以省略,default不能省略
3.如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写。

接口中的静态方法

  • JDK8以后 允许在接口中国定义静态方法,需要用static修饰

接口中静态方法的额定义格式 :
- 格式: public static 返回值类型 方法名(参数列表){ }
- 范例: public static void show(){ }

注意事项:

  • 静态方法只能通过接口名调用,不能同故宫实现类名或者对象名调用

  • public可以省略,static 不可以省略

  • JDK9以后 接口中出现了私有方法

  1. privbate 返回值类型 方法名(参数列表){} private void show(){ }
  2. private static 返回值类型 方法名(参数列表){} private static void method(){ }
public interface InterA {
    public static void show1(){
        System.out.println("show1方法开始执行了");
        show3();
    }
    public static void show2(){
        System.out.println("show2方法开始执行了");
        show3();
    }
    public static void show3(){
    	//必须是static
    	//若上述show1,show2是default,则不需要static
        System.out.println("记录程序运行时的各种细节");
    }
}

[!NOTE] 静态的私有方法,为静态方法服务 普通的私有方法,为默认方法服务

接口的应用(接口多态)

接口类型 j = new 实现类对象(); 编译看左,运行看右

适配器设计模式

  • 设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
  • 使用设计模式是为了可重用代码、让代码更容易被他人理解,保证代码的可靠性、程序的重用性。(设计模式就是多种套路)
  • 适配器设计模式:解决接口与接口实现类之间的矛盾问题
public interface Inter {
    public abstract void method1();
    public abstract void method2();
    ...
    public abstract void method10();
}

//在此创建父类来使InterImpl更加简洁
public abstract class InterAdapter implements Inter {
    //abstract 不让外界创建对象
    @Override
    public void method1() {}
    public void method2();
    ...
    @Override
    public void method10() {}
}

public class InterImpl extends InterAdapter{
    //需要用到哪个方法就重写哪个方法

    @Override
    public void method5() {
        System.out.println("第五个方法");
    }
}

Inter定义了多个抽象方法,但是测试类只需要调用其中的一个方法method5(),于是添加一个类(作为测试类的父类)去重写所有方法,这样测试类就可以按需重写方法了。其中添加的这个类就是适配器


内部类

  • 类的五大成员:属性,方法,构造方法,代码块,内部类
  • 内部类分为: 成员内部类,静态内部类,局部内部类,匿名内部类
  • 在A类的内部定义B类,B类就被成为内部类
  • 内部类表示的事物是外部类的一部分,内部类单独出现没有任何意义

访问特点

  • 内部类可以直接访问外部类的成员,包括私有private
  • 外部类要访问内部类的成员,必须创建对象。

成员内部类

  • 写在成员位置的,属于外部内部类
  • 成员内部类可以被一些修饰符修饰,private、默认、protected、public、static等(用static修饰就是静态内部类了)

获取成员内部类对象的两种方式:
方式一:外部类编写方法,对外提供内部类对象
方式二:直接创建
格式 Outer.Inner oi = new Outer().new Inner();

成员内部类获取外部类的成员变量

public class Outer {
    private int a = 10;//<----sout(Outer.this.a)
    class Inner {
        private int a = 20;//<----sout(this.a)
        private void show() {
            int a = 30;//<----sout(a)
            System.out.println(a);
            System.out.println(this.a);
            System.out.println(Outer.this.a);//此处的Outer是类名
        }
    }
}

静态内部类

  • 是用static修饰的成员内部类
  • 静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象

创建静态内部类对象的格式: 外部类名.内部类名. 对象名 = new 外部类名.内部类名 ();
Outer.Inner oi = new Outer.Inner();

调用非静态方法的格式:
先创建对象,再对象调用

调用静态方法的格式:
外部类名.内部类名.方法名();


局部内部类(了解)

  • 1.将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
  • 2.外界是无法直接使用,需要在方法内部创建对象使用
  • 3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量

匿名内部类**

  • 匿名内部类本质上是隐藏了名字的内部类
	new 类名或接口名(){
		重写方法;
	};
	//注意有分号

接口(实现关系)

public class Student  implements Swim(){	
	@Override
	public void swim(){
		sout("重写的swim方法");
	}
}
//1.把前面的class去掉,剩余的内容变成了一个没有名字的类
//2.这个没有名字的类想要实现Swim接口  
//把Swim写在了大括号的前面,表示这个没有名字的类实现了Swim接口,所以需要在类中重写接口里面的所有抽象方法。
	new Swim(){
		@Override
		public void swim(){
			sout("重写的swim方法")
		}
		//这一部分(匿名内部类的对象)是没有名字的类(Student),他来实现Swim接口
	};

类名(继承关系)

	new Animal(){
		@Override
		public void eat(){
			sout()
		}
	}

应用/拓展

public class Test {
    public static void main(String[] args) {
        //整体理解为Swim接口的实现类对象
        //接口多态:接口类型 j = new 实现类对象();
        Swim s = new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后的swim方法");
            }
        };
        //编译看左边,运行看右边
        s.swim();


        new Swim(){
            @Override
            public void swim() {
                System.out.println("重写之后的swim方法");
            }
        }.swim();//自己调用自己

    }
}

格式的细节: 包含了继承或实现,方法重写,创建对象。整体就是一个类的子类对象或者接口的实现类对象 使用场景: 当方法的参数是接口或者类时。 以接口为例,可以传递这个接口的实现类对象 如果实现类只要使用一次,就可以用匿名内部类简化代码

今日访问 ... 次 | 今日访客 ... 人 | 本页阅读 ...
小站已萌萌哒运行了 0 0 0
已累计耕耘 16 篇博文 · 共 42.69k 个字
总访问量 ...