零碎的Java基础

本文详细介绍了Java中的final和static关键字。final用于修饰变量、方法和类,确保数据不可变,防止方法被重写,以及禁止类被继承。static关键字则用于类级别的成员,包括静态变量、静态方法和静态内部类,使得它们可以在没有对象的情况下被调用。此外,文章还讨论了抽象类与接口的区别,以及equals和==的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关键字

final

修饰数据/变量

数据/变量不可变了。声明数据是常量,可以是编译时常量,也可以是在运行时被初始化后不能被改变的常量。

  • 对于基本类型,final使数值不变。
  • 对于引用类型,final使引用不变,也就不能引用其他对象,但是被引用的对象是可以改变的。

修饰方法

声明方法不能被子类重写
private方法隐式地被指定为final,如果在子类中定义的方法和基类中的一个private方法签名相同,此时子类的方法不是重写基类方法,而是在子类中定义了一个新的方法。

修饰类

声明类不允许被继承。

static

static关键字的作用是方便在没有创建对象的情况下被调用。
被static关键字修饰的不需要创建对象取调用,直接根据类名就可以去访问。因为静态修饰即表示将这个成员/变量/方法称为类所属,而不是对象所属。

修饰类成员即类

普通类不允许声明为静态,只有内部类可以。
非静态内部类依赖于外部类的实例,也就说需要先创建外部类实例,才能用这个实例来创建非静态内部类。而静态内部类不需要。
静态内部类不能访问外部类的非静态的变量和方法。

修饰成员变量

被static修饰的成员被称为类成员/静态成员(相对于对象的属性和方法)。

  • 静态变量:又称为类变量,被所有对象所共享,类所有的实例都共享静态变量,可以直接通过类名去访问,在内存中只有一个副本即只有一份,当且仅当在类初次加载时会被初始化。静态变量也称为类变量,说明这个变量是属于这个类的,而不是属于某对象。
  • 非静态变量:是对象所拥有的,在创建对象时被初始化,存在多个副本,每个对象拥有的副本互不影响。非静态变量也称为实例变量,说明这个变量是属于某对象。每创建一个实例就会产生一个实例变量,它与该实例同生共死。
public class A{
	private int x;//非静态变量,实例变量
	private static int y;//静态变量,类变量
	public static void main(String[] args){
		int x = A.x;//非静态变量x不能在静态块里被引用
		A a = new A();//实例化一个对象
		int x = a.x;
		int y = A.y;//静态变量y直接通过类,y就可以引用
	}
}

修饰方法

静态方法不依赖任何对象就可以进行访问,没有this。
静态方法在类加载时已经存在,它不依赖于任何实例,所以静态方法必须有事先,也就是它不能是抽象方法,即abstract和static不能结合使用。
只能访问所属类的静态字段和静态方法,方法中不能有this和super关键字,因此这两个关键字与具体对象关联。

修饰创建对象

修饰代码块

静态代码块可以置于类的任何地方,在类初次被加载时,会按照static块的顺序来执行,且只会执行一次。

public class A{
	static{
		System.out.println("123");
	}
	public static void main(String[] args){
		A a1 = new A();
		A a2 = new A();//实例化了两次,但只会执行一次,因此输出结果为“123”
	}
}

抽象类和接口

抽象类

抽象类和抽象方法都是用abstract关键字进行声明。如果一个类中包含抽象方法,那么这个类必须声明为抽象类。
抽象类和普通类最大的区别是:抽象类不能被实例化,只能被继承。所以我们可以让子类继承然后实例化子类。

//抽象类
public abstract class AbstractClassExample{//都可见,不同包的也可见
	protected int x;//protected不同包的不可见
	//不写时默认为friendly 为 不同包和子孙类的不可见,当前类和同包的其他类可见。
	privated int y;//privated不同类的都不可见 只能当前类
	
	public abstract void func1();//抽象方法,不能有方法体
	public void func2(){
		System.out.println("func2");
	}
}
//普通类,继承上个抽象类
public class AbstractExtendClassExample extends AbstractClassExample{
	@Overide
	public void func1{
		System.out.println("func1");
	}
}

//实例化
AbstractClassExample ac = new AbstractExtendClassExample();//不能写为 AbstractClassExample ac = new AbstractClassExample();因为AbstractClassExample是抽象类不能被实例化
ac2.func1();

接口

接口用interface关键字来声明。接口是抽象类的延申,在Java 8之前,它可以被看成是一个完全抽象的类,也就是说它不能有任何的方法实现。
从Java 8开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在Java 8之前,如果一个接口想要添加接口的成员(字段+方法)默认是public的,并且不允许被定义为private或protected。
接口的字段都默认为static和final。

//一个接口
public interface InterfaceExample{
	void func1();//构造函数?
	default void fun2(){
		System.out.println("func2");
	}
	int x = 123;
	//int y; y没有被实例化不能这么写
	public int z = 0; //public多余
	//private/protected int k = 0; private和protected都不能在这里用
	//private void func3(); private不能在这里用
}
//继承一个接口
public class InterfaceImplementExample implements InterfaceExample{
	@Overide
	public void func1(){
		System.out.println("func1");
	}
}
//使用 实例化
InterfaceExample ie = new InterfaceImplementExample();//不能写成InterfaceExample ie = new InterfaceExample();因为InterfaceExample是接口,是抽象的,不能直接被实例化
ie.func1();
System.out.println(InterfaceExample.x);

两者区别

  1. 设计层面上来看,抽象类提供了一种IS-A关系(类的父子继承关系),需要满足里氏替换原则,即子类对象必须能够替换掉所有父类对象。而接口更像是一种LIKE-A关系(组合关系),它只提供一种方法实现契约,并不要求接口和实现接口的类具有IS-A关系。(比如空调继承于制冷机,但他还能制热,所以实现加热接口)
  2. 使用上来看,一个类可以实现多个接口,但是不能继承多个抽象类。
  3. 接口的字段只能是static和final类型的,抽象类没有这个限制。
  4. 接口的成员只能是public的,而抽象类的成员可以是多种访问权限。

使用选择

使用接口:

  1. 需要让不相关的类都实现一个方法,例如不相关的类都可以实现Comparable接口中的compareTo()方法。
  2. 需要使用多重继承。

使用抽象类:

  1. 需要在几个相关的类中共享代码。
  2. 需要能控制继承来的成员的访问权限,而不是都是public。
  3. 需要继承非静态和非常量字段。

在多数情况下,接口优先于抽象类,因为它没有抽象类那么严格的类层次结构要求,可以灵活的为一个类添加行为。

equals和==的区别

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值