Java基础——类(学习分享)

介绍

什么是类

类是一个模板,描述一类对象的行为和状态。
类是对象的抽象集合。
比如:

  • 男孩。
  • 女孩。
  • 汽车。

什么是对象

对象是类的一个实例,包括状态和行为。
比如:

  • 狗的状态:名字、颜色、品种;行为:吃、跑、睡、叫。

类的定义

访问权限修饰符 修饰符 class 类名()extends /implements 类名{}
访问权限修饰符:public:共有,可以被其他类或程序访问。
修饰符:

  • abstract:抽象,抽象类不能被实例化,可以有抽象方法和普通方法,可通过子类实例化。
  • final:最终的,被final修饰不能被继承。
  • synchronized:同步,多线程使用。

class:声明类的关键字。
extends :继承其他类。可以继承和使用被继承类的方法和属性。
implements :实现其他接口。需要重写被实现接口的方法。

类的命名规则

大写字母开头,驼峰命名法(即所有首字母大写)。
类名不能使用Java关键字(如:this、int等)。
不能包含嵌入的空格、点、特殊符号(下划线(_)和美元符号($)字符除外)。

类的生命周期

Java源文件经过编译后生成一个后缀名为class的字节码文件,Java类的生命周期就是指一个class文件在Java虚拟机中从加载到卸载的全过程。包括:

  • 加载:

类生命周期的第一阶段,找到需要加载的类并把类的信息加载到JVM的方法区中,然后在堆区中实例化一个Class对象,作为方法区中这个类的信息的入口。

  • 连接:

一般会跟加载阶段交叉进行,主要是做一些加载后的验证工作以及一些初始化的准备工作。包括:验证、准备、解析:

  • 1、验证:类被加载后,首先验证这个类是否合法,保证加载的类是能够被JVM运行的。验证字节码的格式、变量、方法是否重复,类型是否有效。
  • 2、准备:为类的静态变量分配内存,并设为JVM的默认的初值(jvm默认的初值,而不是我们在程序中设定的初值。jvm默认的初值是这样的:基本类型(int、long、short、char、byte、boolean、float、double)的默认值为0。)。不为非静态变量分配内存。引用类型的默认值为null。常量的默认值为我们程序中定义的值。
  • 3、解析:把常量池中的符号引用转换为直接引用。解析阶段,JVM会把所有的类、接口名、字段名、方法名转换位具体的内存地址。
  • 初始化:

如果一类被直接引用,就会触发类的初始化。Java中直接引用的情况:

  • 通过new关键字实例化对象、读取或设置类的静态变量、调用类的静态方法。
  • 通过反射方式执行以上三种行为。
  • 初始化子类的时候,会触发父类的初始化。
  • 作为程序入口直接运行时(也就是直接调用main方法)。

除了以上四种情况,其他使用类的方式叫做被动引用,而被动引用不会触发类的初始化。

  • 使用:

包括主动引用和被动引用。被动引用:

  • 引用父类的静态字段,只会引起父类的初始化,而不会引起子类的初始化。
  • 定义类数组,不会引起类的初始化。
  • 引用类的常量,不会引起类的初始化。
  • 卸载:

使用阶段完成之后,Java类就进入了卸载阶段。需要满足这些条件:

  • 该类所有的实例都已经被回收,也就是Java队中不存在该类的任何实例。
  • 加载该类的ClassLoader已经被回收。
  • 该类对应的java.lang.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。

以上三个条件全部满足,JVM就会在方法区垃圾回收的时候对类进行卸载。
类的卸载过程其实就是在方法区中清空类信息。
Java类的整个生命周期就结束了。

项目中常说的类加载包括:class字节码文件的加载、连接、初始化

类的加载过程

类的加载指的是将.class字节码文件中的二进制数据读入到内存中,将其放在运行时内存区的方法区中,然后在堆区创建一个该对象的java.lang.Class对象,用来封装类在方法区中类的对象。

类加载的最终结果是堆区中的class对象。class对象封装了类在方法区中的数据结构,并提供了访问方法区内数据结构的接口。

  • 加载类的方式:
  • 从本地系统直接加载。
  • 通过网络下载.class文件。
  • 从zip,jar等归档文件中加载.class文件。
  • 从专有数据库中提取.class文件。
  • 将Java源文件动态编译为.class文件。
  • 类加载器:
    在这里插入图片描述

1、BootstrapClassLoader(启动类加载器):

  • 负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,加载System.getProperty(“sun.boot.class.path”)所指定的路径或jar。

2、ExtensionClassLoader(标准扩展类加载器):

  • 负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包。载System.getProperty(“java.ext.dirs”)所指定的路径或jar。

3、AppClassLoader(系统类加载器):

  • 负责记载classpath中指定的jar包及目录中class

4、CustomClassLoader(自定义加载器):

  • 属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现。
  • 类加载器的顺序
  • 加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类。
  • 在加载类时,每个类加载器会将加载任务上交给其父,如果其父找不到,再由自己去加载。
  • Bootstrap Loader(启动类加载器)是最顶级的类加载器了,其父加载器为null。
  • 双亲委派加载机制

如果一个类加载器收到了类加载的请求,首先不会自己尝试去加载这个类,而是把这个请求委托给父类加载器去完成,每一个层次的类加载器都是如此,因此所有的加载请求最终都应该被传送到顶层的启动类加载器中,只有当父类加载器反馈自己无法完成这个加载请求时,子加载器才会尝试自己加载。

  • 使用双亲委派机制的好处

能够有效确保一个类的全局唯一性。当程序中出现多个限定名相同的类时,类加载器在执行加载时,始终只会加载其中的某一个类。

类的基本结构

就是类中包含的内容。

  • 属性:对象数据的描述。
  • 方法:对象的行为。
  • 构造方法:用于实例化对象的。
  • 内部类:在类中声明的类(inner class)。
    块:分静态块和实例块:
  • 静态块:只在类第一次加载的时候调用一次。
  • 实例块:非静态代码块,也称匿名构造方法。在类每次调用构造方法之前调用一次。

类的属性

可以理解为对象的数据。
声明方式:
(访问权限修饰符)(修饰符) 数据类型 属性名 (=初值)

  • 成员变量(实例变量)

类中方法外,非静态。创建对象的时候实例化。

  • 类变量(静态变量)

类中方法外,静态。

  • 局部变量(本地变量或临时变量)

方法会块中。生命周期是从方法的调用到方法调用结束。

类的方法

也称函数。在类中具有一定功能的一段代码。
对象的行为。

  • 声明形式:
(访问权限修饰符) (修饰符) 返回值数据类型 方法名 (形式参数列表){
		//执行语句
		return 具体的返回值;
}
  • 特点

定义方法可以将功能代码进行封装。
便于功能代码的复用。
方法只有被调用才会被执行。
没有返回值,返回值类型用void,方法中的return可以省略不写。
方法中可以调用方法,但是方法中不能在定义方法。

  • 重载

方法名相同、参数不同(数量不同、类型不同、顺序不同)

构造方法

名称与类名相同,没有返回值。
无需手动调用,自动执行的方法。
创建对象就必须要使用构造方法。默认会提供一个无参的构造方法。
构造方法可以在实例化对象时做一些初始化操作。
构造方法不会被显示调用。

类的程序块(代码块)

就像方法,设计一定的功能。
没有名字、参数、没有返回值。只有一对大括号,把内容包裹起来。
每次调用构造方法创建对象之前,系统自动调用一次程序块;多个程序块时会顺序执行。

  • 静态代码块
  • 可以声明输出语句。
  • 随着类的加载而执行。
  • 仅在加载类的时候执行一次。
  • 初始化类中的信息。
  • 只能调用静态的属性和方法,不能调用非静态的属性和方法。
  • 加载顺序早于非静态代码块。
  • 非静态代码块
  • 可以声明输出语句。
  • 随着对象的创建而执行。
  • 每创建一个对象就执行一次。
  • 初始化实例对象的信息。
  • 可以调用静态的属性和方法,也可以调用非静态的属性和方法。
  • 多个代码块时,按顺序先后执行。

类中结构的加载顺序

父类静态属性→父类静态代码块→子类静态属性→子类静态代码块→父类非静态属性→父类非静态代码块→父类构造器→子类非静态属性→子类非静态代码块→子类构造器。

实例代码:
父类:

package com.cui.test.DataType.classloaderorder;
/**
 * java 类中结构的加载顺序
 * @author 17610
 */
public class A {

	private static int numA1;//定义私有化的静态属性
	private int numA2;//定义私有化的非静态属性
	static{//静态代码块
		System.out.println("A类的静态属性:"+numA1);
		System.out.println("A类的静态代码块");
	}
	{//非静态代码块
		System.out.println("A类的非静态属性:"+numA2);
		System.out.println("A类的非静态代码块");
	}
	public A(){//A类的无参构造方法
		System.out.println("A类的构造器");
	}
}

子类:

package com.cui.test.DataType.classloaderorder;
/**
 * java 类中结构的加载顺序
 * @author 17610
 */
public class B extends A{

	private static int numB1;//定义一个静态属性
	private int numB2;//定义一个非静态属性
	static{//静态代码块
		System.out.println("B类的静态属性:"+numB1);
		System.out.println("B类的静态代码块");
	}
	{//非静态代码块
		System.out.println("B类的非静态代码属性:"+numB2);
		System.out.println("B类的非静态代码块");
	}
	public B(){//B类的构造方法
		System.out.println("B类的构造器");
	}
}

测试类:

package com.cui.test.DataType.classloaderorder;
/**
 * Java 类中的结构加载顺序
 * @author 17610
 *	测试类
 */
public class C {

	public static void main(String[] args) {
		A ab = new B();
		System.out.println("=======");
		ab = new B();
		System.out.println("=======");
		A ab2 = new B();
	}
}

运行结果:

A类的静态属性:0
A类的静态代码块
B类的静态属性:0
B类的静态代码块
A类的非静态属性:0
A类的非静态代码块
A类的构造器
B类的非静态代码属性:0
B类的非静态代码块
B类的构造器
=======
A类的非静态属性:0
A类的非静态代码块
A类的构造器
B类的非静态代码属性:0
B类的非静态代码块
B类的构造器
=======
A类的非静态属性:0
A类的非静态代码块
A类的构造器
B类的非静态代码属性:0
B类的非静态代码块
B类的构造器

Java类详解

//package 语句 声明 类的位置,会建立相应的文件夹,存放类
//package 包名;  只能有一条,不能写多个
package org.java;

//import 语句
//一个类可能会需要另一个声明的类作为自己的成员或者方法的局部变量
//若两个类不在同一个包中,就需要导入import语句
//import 类所在的包 的名字
import java.util.*;//包含数据结构类
import java.io.*;//包含所有的输入/输出类
import java.sql.*;//包含数据库类
import java.net.*;//包含所有实现网络功能的类
import java.lang.*;//包含所有的基本类

/*
 面向对象编程:有三个特性,封装性,继承性,多态性
 
java 类总结
  1:类的实现
         包括:类的声明和类体
       1.1:类的声明:
         格式如下:
         (访问权限修饰符) (修饰符) class 类名(){
          			类体
       	 }
     1.2:类体:
         1.2.1变量的声明,刻画属性
         1.2.2方法的定义,刻画功能
         类中声明的非静态变量为:成员变量
         方法体中的变量和方法的参数为:局部变量

 访问权限:
 类的访问权限:
      public:其他包中的类可以访问这个类
       缺省: 这个类只能在本包中进行访问
 成员的访问权限:
     public:都可以访问
     private:只能在本类中进行访问
     protected: 在本包中和子类中能被访问,其他的访问出错
     缺省:在本包中 能被访问
 */
public class Test {
    //Test为类名:合法标识符:字母,下划线,数字和美元组成,第一个字符不能为数字,且拉丁字母首字母大写;

    //变量的声明:成员变量->在整个类内部有效
    //成员变量分为:实例变量 和 类变量(static关键字修饰,也称为静态变量)
    //方法体中声明的变量和方法的参数为:局部变量->只在方法中有效

    //方法:实例方法  和  类方法
    //实例方法:没有static关键字,
    //类方法:加上static 关键字 即为类方法


    //变量的类型:整型,浮点型,字符型等基本类型,和数组,对象,接口等引用类型
    //基本类型数据:
    //    逻辑类型:boolean
    //  整数类型:byte,short,int,long;//分别分配,1,2,4,8 个字节
    //    字符类型:char;//2个字节
    //    浮点类型:float,doble;//分别分配4,8个字节
    // 注意:级别低的变量 赋值给 级别高的变量的时候,会自动进行类型转换
    //      但是级别高的变量 赋值给 级别低的变量的时候,需要显示的类型转换(强转)
    int width;//实例变量
    int height;//实例变量
    String name;//实例变量
    static int cnt;//类变量(静态变量)

    //类的完整性包括 set方法,get方法,toString方法和功能方法,构造方法(无参,有参)

    //功能方法
    //方法的定义包括:方法的声明和方法体
    //格式:  (访问权限修饰符) (修饰符) 返回值类型 方法名{
    //            方法体
    //        }
    //方法的声明:包括 方法名 和方法返回类型
    //如下 int(返回类型)  area(方法名)
    //实例方法:
    //    可以操作实例变量,也可以操作类变量;
    //     也可调用实例方法,也可以调用类方法;
    public int area(int width,int height) {//int height 局部变量
        //成员变量的隐藏:若是 局部变量的名字 和 成员变量 名字相同,那么这个方法隐藏了成员变量
        //可以使用this.成员变量的名字,使成员变量有效
        int tmpData=0;//局部变量,只有初始化之后,才可以使用,否则报错
        cnt++;//实例方法操作 类变量
        System.out.println(tmpData);
        this.width=width;
        this.height=height;
        return this.height*this.width;
    }
    //多态包括:两种:重写(overload) 和 重载(Override)
    //重载:方法的名字相同,但是 参数个数不同 或者 参数类型不同
    //重载  area方法->方法类型不同
    //重写:重写父类的方法 或者称为 覆盖父类的方法
    public double area(double x,double y) {
        x=width;//this 可省略,操作实例变量
        y=this.height+1.0;
        return x*y;
    }

    //类方法:加上static关键字
    //         类方法只能操作类变量,不能操作实例变量
    //        只能调用类方法,不能调用实例方法
    public static int count() {
        cnt++;//类方法 操作类变量
        Test.cnt++;//或者通过 类名.类变量操作
        return cnt;
    }

    //构造方法:无参
    //构造方法的名字和类名一样
    public Test() {
        super();
    }
    //构造方法:有参(也属于重载)
    public Test(int width, int height, String name) {
        super();
        this.width = width;
        this.height = height;
        this.name = name;
    }

    //get,set方法
    public int getWidth() {
        return width;
    }
    public void setWidth(int width) {
        this.width = width;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    //重写object里面的toString()方法
    //创建类时,若是没有指明父类,那么会默认为object类
    //会继承object里面的所有方法
    //所以这里才能重写 父类object类里面的toString方法
    //重写
    @Override
    public String toString() {
        return "Test [width=" + width + ", height=" + height + ", name=" + name + "]";
    }
}

参考:
https://blog.csdn.net/zixiaoxian/article/details/87990604
https://blog.csdn.net/weixin_37766296/article/details/80545283
https://blog.csdn.net/u014745069/article/details/82655339
https://www.cnblogs.com/NirobertEinteson/p/12008436.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值