static关键字
实例属性:
实例属性是每个对象各自持有的独立空间,为多份,对象单方面修改,不会影响其他对象。
静态属性:
静态属性是整个类共同持有的一份共享空间,只有一份,任何对象修改,都会影响其他对象。
静态对象概念:
- 静态(static)可以修饰属性和方法。
- 被static修饰的属性称为静态属性,被static修饰的方法称为静态方法。
- 静态成员是全类所有对象共享的成员。
- 在全类中只有一份,不会因为创建多个对象而产生多份。
- 可直接通过类名访问。
public class Test01 {
public static void main(String[] args) {//静态方法
// TODO 自动生成的方法存根
MyClass mc1=new MyClass();
mc1.b=10;//访问类共享空间(全类独有一份)
MyClass mc2=new MyClass();
mc2.b=20;
System.out.println(mc1.b);
System.out.println(mc2.b);
//直接通过类名访问静态变量
System.out.println(MyClass.b);
}
}
class MyClass{
int a;
static int b;//静态属性
}
静态方法:
已知的静态方法:
- Arrays.copyOf();
- Arrays.sort();
- Math.random();
- Math.sqrt();
- …
均可以使用类名直接调用。
静态的特点:
- 静态方法允许直接访问静态成员。
- 静态方法不能直接访问非静态成员。
- 静态方法中不允许使用this或者super关键字。
- 静态方法可以继承,不能重写、没有多态。
public class Test03 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
TestStatic03.filed1=“静态变量”;
TestStatic03.method1();
TestStatic03.method2();
}
}
class TestStatic03{
static String filed1;//静态属性
int filed2;//实例属性
public static void method1() {//静态方法
//静态方法允许直接访问静态成员
System.out.println(filed1);
//静态方法不允许直接访问非静态成员
//System.out.println(filed2);
}
public static void method2() {//静态方法
//super();
/*
* 实例变量含义this或super关键字
*/
//this.method1();
method1();
}
}
类加载
- 加载时机:
创建对象。
创建子类对象。
访问静态属性。
调用静态方法。
Class.forName(“全限定名”);
静态代码块
类加载时,触发静态代码块的执行,仅执行一次。
执行地位:静态属性初始化之后。
作用:可为静态属性赋值,或必要的初始化行为。
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException {
// TODO 自动生成的方法存根
new Super();
new Super();
Sub.method();//通过类名访问
Class.forName(“com.qf.classload.Sub”);//主动触发类的加载
}
}
class Super{
String filed=“实例属性”;
/*
* {动态代码块}
/
{
System.out.println(filed);
System.out.println(“动态代码块”);
}
public Super() {}
}
class Sub{
static String filed=“静态属性”;
String filed1=“静态属性1”;
/
* static{静态代码块}
*/
static {
System.out.println(filed);
//System.out.println(filed1);//只能访问静态属性
System.out.println(“静态代码块”);
}
public static void method() {
System.out.println(“静态方法------”);
}
}
总结
- static修饰的成员为静态成员,无需创建对象,可以直接通过类名访问。
- 静态方法不能直接访问非静态成员。
- 静态方法中不能使用this或super。
- 静态方法可以继承,不能重写、没有多态。
- 静态代码块在类加载时被执行、且只有执行一次。
final关键字
最终的
- final修饰的类为最终类、final修饰的方法为最终方法、final修饰的变量为最终变量。
final修饰
- final修饰的类:此类不能被继承。
- final修饰的方法:此方法不能覆盖。
- final修饰的变量:此变量值不能被改变。
实例常量
实例常量不再提供默认值,必须手动赋初始值。
赋值时机:显示初始化、动态初始化、构造方法。
静态常量
静态常量不再提供默认值,必须手动赋初始值。
赋值时机:显示初始化、静态初始化。
对象常量
final修饰基本类型:值不可变。
final修饰引用类型:地址不可变。
public class Test02 {
public static void main(String[] args) {
final int a=10;
final int[] nums=new int[] {11,22,33};
nums[0]=55;//地址没有改变
System.out.println(nums[0]);
Stu s=new Stu();
//s.name=“joy”;
System.out.println(s.name);
}
}
final class Stu{
final String name=“tom”;//不能改变
final public void method() {}//不能覆盖
}
//class Student extends Stu{}//final修饰的类:此类不能被继承。
总结
- final修饰的类不能继承、final修饰的变量只能赋值一次、final修饰的方法不能覆盖。
- final修饰基本类型:值不可变;final修饰引用类型:地址不可变。
接口
接口语法
- 接口相当于特殊的抽象类,定义方式、组成部分与抽象类类似。
- 使用interface关键字定义接口。
- 没有构造方法,不能创建对象。
- 只能定义公开静态常量、公开抽象方法。
与抽象类不同
- 所有属性都是公开静态常量,隐式使用public static final修饰。
- 所有方法都是公开抽象方法,隐式存在public abstract修饰。
- 没有构造方法、动态代码块、静态代码块。
接口概念
- 接口是一种能力和约定。
- 接口的定义:代表了某种能力。
- 方法的定义:能力的具体要求。
- 接口支持多实现,可为类扩充多种能力。
- 经验:java为单继承,当父类的方法种类无法满足子类需求时,可实现接口的扩充子类能力。
接口的规范
- 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
- 实现接口中的抽象方法时,访问修饰符必须是public。
接口引用
- 同父类一样,接口也可声明为引用,并指向实现类对象。
- 仅可调用接口中所有声明的方法,不可实现类中独有的方法。
- 可强转回实现类本身类型,进行独有方法调用。
接口的多态
不同引用所能看到的对象范围不同,只能调用自身类型中所声明的部分。
常见关系
- 类与类:单继承。extends 父类名称
- 类与接口:多实现。implements 接口名称1,接口名称2,接口名称3…
- 接口与接口:多继承。extends 父接口1,父接口2,父接口3,…
public class Test01 {}
/*
接口支持多级继承、接口支持多继承
*/
interface IA{
void m1();
}
interface IB{
void m2();
}
interface IC extends IA,IB{//接口与接口:多继承
void m3();
}
class MyClass implements IC{// 类与接口:多实现
public void m1() {}
public void m2() {}
public void m3() {}
}
常量接口
- 将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理,提高代码可读性。
public interface Test02 {//定义接口
//定义接口常量
//计算
public static final double PI = 3.14159265358;
//状态
public static final int RED = 1;
public static final int YELLOW = 2;
public static final int GREEN = 3;
}
回调原理
接口回调:先有接口使用者,后有接口的实现者。
public class Test01 {
public static void main(String[] args) {
Computer computer = new Computer();
Fan f = new Fan();
Lamp l = new Lamp();
Udisk m = new Udisk();
computer.on(f);
computer.executeUSB();
computer.on(l);
computer.executeUSB();
computer.on(m);
computer.executeUSB();
}
}
//接口
interface USB{
//服务方法(做什么,由实现者指定)
public abstract void service();
}
//接口的使用者
class Computer{
//引用接口
USB usb;
public void on(USB usb) {//接口作为参数
this.usb = usb;
}
public void executeUSB(){
usb.service();
}
}
//接口的实现者
class Fan implements USB{
public void service() {
System.out.println(“接口风扇”);
}
}
class Lamp implements USB{
public void service() {
System.out.println(" 接口灯");
}
}
class Udisk implements USB{
public void service() {
System.out.println(" 接口USB");
}
}
接口的好处
- 程序的耦合度降低。
- 更自然使用多态。
- 设计与实现完全分离。
- 更容易搭建程序框架。
- 更容易更换具体实现。
接口实现科特巴赫猜想
public class GoldBach1 {
//并行,先有接口调用者,后有接口实现者
public static void main(String[] args) {
checkGoldBach(8,new IsPrime());
}
public static void checkGoldBach(int num,MathTool tool) {
for(int i=2;i<num/2;i++) {
if(tool.isPrime(i)&&tool.isPrime(num-i)) {
System.out.println(i+"\t"+(num-i));
}
}
}
}
//接口:约定(建立标准)
interface MathTool{
public abstract boolean isPrime(int n);
}
//接口实现类
class IsPrime implements MathTool{
public boolean isPrime(int n) {
for(int i=2;i<n;i++) {
//求质数,质数的因子只有1和其本身
if(n%i==0) {
return false;
}
}
return true;
}
}
内部类与常用类
内部类的分类
- 成员内部类、静态内部类、局部内部类、匿名内部类
概念
- 在一个类的内部再定义一个完整的类。
- 特点:
- 编译之后可生成独立的字节码文件。
- 内部类可直接访问外部类的私有成员,而不破坏封装。
- 可为外部类提供必要的内部功能组件。
成员内部类
- 在类的内部定义,与实例变量、实例方法同级别的类。
- 外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
-Outer out=new Outer;
Inner in=out.new Inner(); - 当外部类、内部类存在重名属性时,会优先访问内部类的属性。
- 成员内部类不能定义静态成员。
public class TestInstance {
public static void main(String[] args) {
Outer out=new Outer();
out.m1();
//外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象
Outer.Inner in=out.new Inner();
in.m2();
}
}
class Outer{
int a=10;//实例变量
public void m1() {}//实例方法
class Inner{//成员内部类,在类的内部定义,与实例变量、实例方法同级别的类
int b=20;//内部类实例
/*
* 不能定义静态成员,因为成员内部类不能脱离外部类对象而独立存在
* static String field=“Inner”;
*/
public void m2() {
System.out.println(Outer.this.a);
System.out.println(Outer.Inner.this.b);
System.out.println(b);
System.out.println(“m2() in Inner”);
}
}
}
静态内部类
- 不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
- 只能直接访问外部类的静态成员,实例成员需要实例化外部对象。
-Outer.Inner inner=new Outer.Inner();
Outer.Inner.show();
public class TestStaticInner {
public static void main(String[] args) {
//不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
System.out.println(Outer.Inner.b);
// 只能直接访问外部类的静态成员,实例成员需要实例化外部对象。
Outer.Inner in =new Outer.Inner();
in.m2();
}
}
class Outer{
private static int a=20;
String s=“filed”;
//静态内部类
static class Inner{
static int b=10;
public void m2() {//实例成员方法
System.out.println(Outer.a);
/*
* 非静态不能访问
* System.out.println(Outer.s);
*/
}
}
}
局部内部类
- 定义在外部类的方法中,作用范围和创建对象范围仅限于当前方法。
- 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
- 限制类的使用范围。
public class TestLocalInner {
public static void main(String[] args) {
Outer out=new Outer();
out.m1();
}
}
class Outer{
int a=11;
//外部实例方法
public void m1() {//外部类方法
//局部内部类
class Inner{
int c=30;
public void m2() {
//访问外部类的实例成员
System.out.println(a);
System.out.println(Outer.this.a);
System.out.println©;
System.out.println(this.c);
System.out.println(“Inner m2()”);
}
}
//创建局部内部类对象
Inner in=new Inner();
System.out.println(in.c);
in.m2();
}
}
匿名内部类
- 没有类名的局部内部类,一切特征与局部内部类相同。
- 必须继承一个父类或者实现一个接口。
- 定义类、实现类、创建对象的语法 合并,只能创建一个该类的对象。
public class Test10 {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Lamp lamp=new Lamp();
//局部内部类,在main()方法中
class Red implements Light{
public void shine() {
System.out.println(“shine in Red”);
}
}
Red r=new Red();
lamp.on®;
//匿名内部类, 没有类名的局部内部类
Light light=null;
//定义类、实现类、创建对象的语法 合并,只能创建一个该类的对象。
light=new Light() {
public void shine() {
System.out.println(“shine in Yellow”);
}
};//分号引回
lamp.on(light);
}
}
//接口
interface Light{
void shine();
}
class Lamp{
public void on(Light light) {//引用接口作为参数
light.shine();
}
}
Object类
- 超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
- 任何类,如果没有书写extends显示继承某个类,都默认直接继承Object类,否则为间接继承。
- Object类中所定义的方法,是所有对象都具备的方法。
- Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。
public class TestBasicObject {
public static void main(String[] args) {
}
public static void m1(Object o) {//Object作为方法形参
}
public static Object m2() {//Object作为方法返回值
return null;
}
}
class MyClass{//默认extends Object
}
getClass()方法
- public final Class<…> getClass(){}
- 返回引用中存储的实例对象类型。
- 应用:通常用于判断两个引用中实际存储对象类型是否一致。
hashCode()方法
- public int hashCode(){}
- 返回该对象的十六进制的哈希码值。
- 哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
- 哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回不同哈希码。
public class TestToStringMethod {
public static void main(String[] args) {
//获取对象字符串表现形式
Object obj=new Object();
System.out.println(obj.toString());
System.out.println("--------------------------");
Student stu=new Student();
System.out.println(stu.toString());
System.out.println(stu);//打印对象,实质是该对象的toString()结果
System.out.println("--------------------------");
//Teacher tea=new Teacher();
System.out.println(stu.hashCode());//哈希码
System.out.println(stu.getClass());//返回引用中存储的实例对象类型
System.out.println(stu.getClass().getName());
System.out.println(Integer.toHexString(stu.hashCode()));
}
}
class Student{}
class Teacher{}
toString()方法
- public String toString(){}
- 返回该对象的字符串表示。
- 可以根据程序需求 覆盖该方法,如展示对象各个属性值。
public class TestMethodToString {
public static void main(String[] args) {
Worker worker=new Worker();
worker.name=“jack”;
worker.age=22;
worker.sex=“男”;
worker.salary=8000;
System.out.println(worker);//对象默认调用toString()方法
}
}
class Worker{
String name;
int age;
String sex;
double salary;
@Override
public String toString() {//覆盖toString方法,展示对象各个属性值
return “Worker [name=” + name + “, age=” + age + “, sex=” + sex + “, salary=” + salary + “]”;
}
}
equals()方法
- public boolean equals(Object obj){}
- 默认实现为(this==obj),比较两个对象地址是否相同。
- 可进行覆盖,比较两个对象的内容是否相同。
equals()方法覆盖步骤
- 比较两个引用是否指向同一个对象。
- 判断obj是否为null。
- 判断两个引用指向的实际对象类型是否一致。
- 强制类型转换。
- 依次比较各个属性值是否相同。
public class TestMethodEquals {
public static void main(String[] args) {
Student1 s1=new Student1(“tom”,20,“男”,96);
Student1 s2=new Student1(“maly”,22,“女”,88);
Student1 s3=new Student1(“jack”,24,“男”,90);
System.out.println(s1.equals(s1));
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
/*
* equals()比较的是地址,适用于引用数据类型
* 比较的是内容,适用于基本数据类型
* 返回布尔类型
*/
System.out.println("---------------------------");
Student1 s4=new Student1(“maly”,20,“女”,88);
Student1 s5=new Student1(“sale”,22,“女”,94);
System.out.println(s4.equals(s5));
}
}
class Student1{
String name;
int age;
String sex;
double score;
public Student1(String name, int age, String sex, double score) {
super();
this.name = name;
this.age = age;
this.sex = sex;
this.score = score;
}
//覆盖超类方法,让equals()实现比较内容
public boolean equals(Object obj) {
//1. 比较两对象地址是否一样
if(thisobj) {
return true;
}
//2.确认对象不能为null
if(objnull) {
return false;
}
//3.确认类型
if(this.getClass()!=obj.getClass()) {
return false;
}
//4.转型
Student1 stu=(Student1)obj;
//5.比较内容
/* if(this.namestu.name&&this.agestu.age&&this.sexstu.sex&&this.scorestu.score) {
return true;
}
*/ if(this.name.equals(name)&&this.agestu.age&&this.sex.equals(sex)&&this.score==stu.score) {
return true;
}
return false;
}
}