类和对象

类是对象的抽象,对象是类的具体。类是概念模型,定义对象的所有特性和所需的操作,对象是真实模型,是一个具体的实体。

类是描述了一组有相同特性(属性)和相同行为(方法)的一组对象的集合。

对象所拥有的特征在类中表示时称为类的属性,执行的操作称为类的方法。

类是构造面向对象程序的基本单位,抽取了同类对象的共同属性和方法形成的“模版”。对象是实体的描述,要创建才存在,有了对象才能对对象进行操作。

抽象类abstract

一个类中没有足够的信息来描绘一个具体的对象,这个类称为抽象类

抽象方法没有方法体,必须在抽象类中

抽象类中可以有具体方法

子类重写父类时,必须重写父类所有的抽象方法

抽象类不能实例化,即不能使用new关键字创建对象

public abstract class Shape{
public int width;
public int height;
public Shape(int width, int height){
this.width = width;
this.height = height;
}
public abstract double area();
}
public class Square extends Shape{
public Square(int width, int height){
super(width, height);
}
@Override
public double area(){
retrun width * height;
}
}

构造函数

构造函数特点:

函数名与类名相同

不用定义返回值类型

不可以写return语句

作用:

给对象进行初始化

构造函数对象一建立就会调用与之对应的构造函数,可用于给对象进行初始化,当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数,当自己定义了构造函数后,默认的空构造函数就不存在了。

多个构造函数是以重载的形式存在的。

构造函数示例👇

class Person{
Person(){
System.out.println("Person run");
}
}
class PersonDemo{
public static void main(String[] args){
Person p = new Person();
}
}

构造代码块👇

{
System.out.println("person code run");
}

构造代码块中,对象一建立就立即运行,而且优先于构造函数执行。构造代码块中定义的是不同对象具有共性的初始化内容。

构造代码块和构造函数的区别:

构造代码块是给所有对象进行统一初始化;而构造函数是给对应的对象初始化。

接口

接口由全局常量和公共的抽象方法组成。

⚠️接口没有构造方法,不能被实例化

接口可以继承其他接口。子接口可以对父接口的方法和常量进行重写

public interface MyInterface{ //具有public的接口允许任何类使用,没有public的将局限于所属的包
String name; //不合法,变量name必须初始化
int age = 20; //合法,等同于public static final int age = 20;
void getInfo(); //方法声明,等同于public abstrct void getInfo();
}

一个类可以实现多个接口,用implements关键字,也是Java为单继承灵活性不足所做的补充

⚠️implements必须放在extends部分之后

内部类

在类的内部定义另一个类,内部类Inner,外部类Outer(最外层的类叫顶层类)

内部类可以很好的实现隐藏,内部类拥有外部类的所有元素的访问权限

public class Test{
public class InnerClass{ //内部类与外部类不能重名
public int getSum(int x, int y){
return x+y;
}
}
public static void main(String[] args){
Test.InnerClass ti = new Test().new InnerClass();
//在外部类中可以直接通过InnerClass ic = new InnerClass()访问
int i = ti.getSum(2, 3);
System.out.println(i);
}
}

实例内部类

在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例

在实例内部类中,可以直接访问外部类的所有成员

外部类必须通过内部类的实例访问内部类的成员

静态内部类

static class Inner{}
public class Outer{
int a1 = 0; //实例变量
static int b1 = 0; //静态变量
static class Inner{
int a = 0; //实例变量
static int b = 0; //静态变量
Outer o = new Outer;
int aa = o.a1; //访问
int bb = b1; //访问
}
}
class OtherClass{
Outer.Inner oi = new Outer.Inner();//在创建静态内部类的实例时,不需要创建外部类的实例
int a2 = oi.a; //访问
int b2 = Outer.Inner.b; //访问
}

局部内部类

public class Test{
int a = 0;
int c = 0;
public void method(){
int b = 0;
final int c = 0;
class Inner{ //局部内部类不能使用访问控制修饰符和static修饰符
//不能定义static成员
int a2 = a ; //可以访问外部类的所有成员
//int b2 = b;编译出错
int c2 = c; //只能访问当前方法中final类型的参数与变量
int c3 = Test.this.c; //访问外部类中的同名成员
}
Inner i = new Inner();//只在当前方法中有效
}
}

访问控制修饰符

对类成员的限制是面向对象程序设计的一个基础,有利于防止对象的误用。信息隐藏是OOP最重要的功能之一,也是使用访问修饰符的原因。

private

只能被该类自身的方法访问和修改,不能被其他类(包括子类)访问和引用,具有最高的保护级别。

默认

只能被用一个包中的类访问和引用,又称为包访问性package private

类内的成员如果没有访问控制符,也说明它们具有包访问性,或称为友元friend

protected

类自身、与它在同一包中的其他类、其他包中的子类。

public

只要包中的其他类在程序中使用import语句引入,就可以访问和引用。

每个程序的主类必须是public类,设定为这个类对外的接口部分,数据封装思想的体现。

static关键字(静态变量和静态方法)

在类中,使用static修饰符修饰的属性(成员变量)称为静态变量,也可以称为类变量;常量称为静态常量;方法称为静态方法或类方法;它们统称为静态成员。

被修饰的成员具备以下特点:

随着类的加载而加载(类一加载到内存中,静态static就已经加载到内存空间/方法区中,反之随着类的消失而消失,生命周期最长)

优先于对象存在

被所有对象所共享

可以直接被类名调用(类名.静态成员)

使用注意:

静态方法只能访问静态成员

静态方法中不可以写this,super关键字

主函数是静态的

static修饰的成员变量和方法,从属于类;普通变量和方法,从属于对象

静态变量

类的成员变量分为静态变量和实例变量两种

静态变量:

运行时,Java虚拟机只为静态变量分配一次内存,在加载类的过程中完成内存分配

在类的内部,可以在任何方法内直接访问静态变量

在其他类中,可以通过类名访问该类中的静态变量

实例变量:

每创建一个实例,Java虚拟机就会为实例变量分配一次内存

在类的内部,可以在非静态方法中直接访问实例变量

在本类的静态方法或其他类中则需要通过类的实例对象进行访问

eg👇

public class StaticVar{
public static String str1 = "Hello";
public static void main(String[] args){
String str2 = "World!";
//直接访问
String accessVar1 = str1 + str2;
System.out.println(accessVar1);//HelloWorld!
//通过类名访问
String accessVar2 = StaticVar.str1 + str2;
System.out.println(accessVar2);//HelloWorld!
//通过对象svt1访问
StaticVar svt1 = new StatcVar();
svt1.str1 = svt1.str1 + str2;
String accessVar3 = svt1.str1;
System.out.println(accessVar3);//HelloWorld!
//通过对象svt2访问
StaticVar svt2 = new StaticVar();
String accessVar4 = svt2.str1 + str2;
System.out.println(accessVar4);//HelloWorld!World!
}
//静态变量是被多个实例共享的
}

静态方法

分为静态方法和实例方法

静态方法不需要通过它所属的类的任何实例就可以被调用,因此不能使用this和super关键字,也不能直接访问所属类的实例变量和实例方法,但是可以直接访问所属类的静态变量和静态方法。

在实例方法中可以直接访问所属类的静态变量、静态方法、实例变量和实例方法

public class StaticMethod {
public static int count = 1; // 定义静态变量count
public int method1() {
// 实例方法method1
count++; // 访问静态变量count并赋值
System.out.println("在静态方法 method1()中的 count="+count); // 打印count
return count;
}
public static int method2() {
// 静态方法method2
count += count; // 访问静态变量count并赋值
System.out.println("在静态方法 method2()中的 count="+count); // 打印count
return count;
}
public static void PrintCount() {
// 静态方法PrintCount
count += 2;
System.out.println("在静态方法 PrintCount()中的 count="+count); // 打印count
}
public static void main(String[] args) {
StaticMethod sft = new StaticMethod();
// 通过实例对象调用实例方法
System.out.println("method1() 方法返回值 intro1="+sft.method1());
// 直接调用静态方法
System.out.println("method2() 方法返回值 intro1="+method2());
// 通过类名调用静态方法,打印 count
StaticMethod.PrintCount();
}
}
//在静态方法 method1()中的 count=2
//method1() 方法返回值 intro1=2
//在静态方法 method2()中的 count=4
//method2() 方法返回值 intro1=4
//在静态方法 PrintCount()中的 count=6

静态代码块

指Java类中的static{}代码块,主要用于初始化类,为类的静态变量赋初始值,提升程序性能。

特点:

类似于一个方法,但不可以存在于任何方法体中

可以置于类中的任何地方,可以有多个静态初始化块

Java虚拟机在加载类时执行静态代码块,所以将只需要进行一次的初始化操作放在static代码块中执行

如果有多个代码块,按在类中出现的顺序依次执行

不能直接访问类的实例变量和实例方法嘛,需要通过类的实例对象访问

为什么不把所有的成员都定义为静态static

对象在被用完后会被回收,但是static的数据生命周期特别长,用完后还会一直存在,会存在垃圾

要区分什么数据是对象特有的,什么数据是多个对象共享的

主函数

public:代表着该函数的访问权限是最大的

static:代表主函数随着类的加载就已经存在了

void:主函数没有具体的返回值返回给虚拟机JVM

main:不是关键字,但是是主函数特有的,可以被JVM识别

String[] args:函数的参数,参数类型是一个数组,数组中的元素是字符串

JVM在调用主函数时,传入的是new String[0],作用:可以往参数里传入数据,在主函数里就可以拿到参数。

final修饰符

表示对象是最终形态的,不可改变的。

⚠️:

final用在变量的前面表示变量的值不可以改变,此时变量可以称为常量

final用在方法的前面表示方法不可以被重写

final用在类的前面表示该类不能有子类,即该类不可以被继承

final修饰变量

即成为常量,只能赋值一次

final修饰的局部变量必须使用之前被赋值一次才能使用

final修饰的成员变量在声明时没有赋值的叫“空白final变量”。空白final变量必须在构造方法或静态代码块中初始化

eg👇

public class FinalDemo{
void doSomething(){
final ine e;//声明局部变量
e = 100;//必须在使用之前赋值
final int f = 200;//声明的同时赋值
}
//声明成员变量
final int a = 5;
final int b; //以上为实例变量,其中b为空白final变量
final static int c = 12;
final static int d;//以上为静态变量,其中d为空白final变量
static{
d = 32;//需要在静态代码块中初始化
}
FinalDemo(){
b = 3;//需要在构造方法中初始化
}
}

final修饰引用类型变量

对于引用类型变量而言,它保存的仅仅是一个引用,final仅保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象可以发生改变。

eg👇

//部分省略

public static void main(String[] args){

final int[] iArr = {5, 6, 12, 9};//iArr是一个引用变量

Array.sort(iArr);//对数组元素排序,合法

iArr[2] = -8;//对数组元素赋值,合法

//iArr = null;//对iArr重新赋值,🙅

final Person p = new Person(45);//p是一个引用变量

p.setAge(23);//改变Person对象的age实例变量,合法

//p = null;//对p重新赋值,🙅

}

⚠️:在使用final声明变量时,要求全部的字母大写

如果一个程序中的变量使用public static final声明,则此变量将称为全局变量

public static final String SEX = "female";

final修饰方法

final修饰的方法不可被重写,可以被重载

对于一个private方法,因为仅在当前类中可见,其子类无法访问该方法,所以子类无法重写该方法。如果子类定义一个与父类private方法有相同方法名、形参列表、返回值类型的方法,不算重写,只是重新定义了一个新方法。因此,即使使用final修饰一个private的方法,依然可以重新定义一个相同的方法。

eg👇

public class FinalMethodTest{
public final void test(){
}
}
class Sub extends FinalMethodTest{
public void test(){
//将出现编译错误,不能重写final方法
}
}
public class PrivateFinalMethodTest{
private final void test(){
}
}
class Sub extends PrivateFinalMethodTest{
public void test(){
//不会出现错误,不算重写
}
}

final修饰类

final修饰的类不能被继承

eg👇

final class SuperClass{
}
class SubClass extends SuperClass{//编译错误
}