类和对象、设计模式、类加载

一、类和对象的定义

类:具有一系列相同的属性和行为的物体

public class TestDemo{//类命名:驼峰命名法
    public static void main(String[] args) {//主函数
       People people = new People("不吃香菜","女",2);
        //new:1.在堆上开辟内存 jmap - histo:live进程号>1.log
        //    2.()调用无参构造函数(用来初始化当前对象属性)
        String name = people.getName;
        System.out.println(name);
        people.play();
    }
}

常见访问限定符:public 默认 protected private

public class People{
    //实例变量(所有函数共用一份成员变量) 默认this 指向当前对象
    private String name,sex;
    private int age;
    //Alt+Insert -> 初始化
    //构造函数/方法 -> 初始化成员变量,给类型默认值
    //如果当前类中没有自定义构造函数,JVM默认生成无参构造函数 类型默认值
    //如果自己实现了构造函数,JVM不会再生成无参构造
    public People(String name, String sex, int age) {//发生命名冲突时,必须显示this
        this.name = name;//变量 就近原则
        this.sex = sex;
        this.age = age;
    }
    //行为:成员方法/实例方法(函数)
    public void play(){
        System.out.println(this.name+"打王者荣耀");
    }
    public String getName(){
        return name;
    }
}

二、对象大小判断

对象大小:对象头(16) + 实例变量 + 内存填充(以16为单位进行内存对齐)
对象头:虚拟机64位:16,虚拟机32位:8
具体判断方法:

  • 首先建立文件TestDemo.java和一个空类People.java
    在这里插入图片描述
    在这里插入图片描述
  • 在当前目录下打开命令窗口,通过javac编译测试文件,java运行文件
    在这里插入图片描述
    注意: 一个类对应一个字节码文件(如下)
    在这里插入图片描述
  • 在该目录下重新打开一个命令窗口,通过jps查看当前正在运行的java程序,找到TestDemo对应的进程号,运用命令(jmap-histo:live 进程号)查看堆上活着的TestDemo程序,将查找到的信息通过输出符号(>)输出到指定文件1.log
    在这里插入图片描述
  • 打开文件1.log,通过查找 People 可以看到定义的空类在堆上占用了16个字节
    在这里插入图片描述
  • 在People中定义变量
    int a;
    static int b;
    int c;
    其中,a,c称为实例变量,b称为静态变量(static关键字中详细介绍)
    定义之后重新运行程序,进行上述过程查看该类所占字节数
    在这里插入图片描述

三、函数重载

特点:

  1. 同一个类
  2. 函数名相同参数列表不同(类型、个数)
public void eat(){
        System.out.println("吃饭");
        eat("zs");//调用下边的函数
    }
    public void eat(String name){
        System.out.println("指定"+name+"吃饭 ");
    }
public People(String name, String sex, int age) {
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    public People(){//无参函数调用有参函数
        this("zs","男",1);//this调用构造函数
    }

重载和重写的区别?

  • 方法的重载和重写都是实现多态的方式,区别在于 重载 实现的是 编译时 的多态性,而 重写 实现的是 运行时 的多态性。
  • 重载一个类中,函数名相同、参数列表不同(参数类型不同、参数个数不同或者二者都不同)。
  • 重写子类对父类 的方法进行重写。参数相同,返回值类型可以不相同,但是必须是父类返回值的派生类(即外壳不变,核心重写)。重写的好处在于子类可以根据需要,定义特定于自己的行为。

四、常用关键字

this

  • 如果 局部变量 和 成员变量 产生命名冲突,需要显示指明当前对象 this.name = name;
  • 构造函数重载:
    1)构造函数之间不能用 this() 相互调用
    2)this() 调用构造函数时,不能在成员函数当中调用
    3)当前构造函数不能通过 this() 调用多个构造函数
    注意:this() 调用 必须位于当前构造函数有效代码(不包含注释)第一行

super

  • 用于在子类构造函数中调用父类的构造
  • 只能在构造函数之间调用,不能在成员方法中使用super()
    注意:必须位于当前构造函数有效代码第一行

final

修饰:
变量 final int INITSIZE = 10;// 常量
方法 final void fun(){ } //不允许重写
final class String( ) //不能被继承

static

static可以修饰变量、方法、类。
成员变量 = 实例变量 + 静态变量
静态变量又称为类变量,用static关键字修饰

class A{
	int a;//实例变量
	static int b;//静态变量
}

(一)静态变量 和 实例变量 区别?

  1. 存储位置不同
    实例变量 -> Java 内存中
    静态变量 -> 方法区
  2. 是否和对象有关
    实例 变量:与对象有关。随着对象创建二存在,随着对象被回收而释放。实例化一次,对应一个实例变量的生成(实例变量所属于对象)。
    静态变量:跟对象无关,只与类有关。随着类的加载而存在,随着类的消失而消失。一个类唯一只有一份静态变量(静态变量所属于类)。
  3. 调用
    实例变量:只能被 对象 调用。
    静态变量 :可以被 对象 调用。

(二)静态方法 和 实例方法的区别?

  1. 实例方法
    属于 对象 ,必须先实例化,通过 (对象.方法名) 调用,可以访问 实例成员静态成员。实例方法中可以使用 this、super关键字(this -> 指向当前对象、super -> 指向父类。
  2. 静态方法
    属于,可以直接通过 (类.方法名) 调用,只能访问 静态成员。静态方法不能被重写,private方法不会被重写。

内部类

Java 一个类中可以嵌套另外一个类,称为内部类。

  • 如果内部类与外部类没有同名方法或属性,内部类可以直接调用外部类的方法和字段
  • 如果内部类同名方法或属性,必须使用"外部类名.this.方法名/属性"格式调用
class SingleLink{
	private Node head;
	//内部类
	class Node{
		private int value;
		public void fun(){
			head = null;//若需要直接访问外部类,则需要设计为实例内部类
			//实例内部类 head前面隐含了 SingleLink。this.	
		}
		static public void fun(){
			//若不需要访问外部类,则设计为静态内部类	
			//静态内部类 不包含 SingleLink。this.
		}
	}
}
非静态内部类
  • 非静态内部类必须先实例化外部类,然后创建内部类的对象来实现。

使用示例:
在这里插入图片描述

静态内部类

静态内部类使用 static 关键字定义,静态内部类不需要创建外部类来访问,可以直接访问
在这里插入图片描述

  • 注意:静态内部类无法访问外部类的成员。
  • 实例内部类相比与静态内部类有额外的开销,因为通过Out拿到了外部类引用,所以它包含外部类的this。

类的初始化顺序

静态变量 静态块 实例变量 实例块 构造函数
代码测试:

class InstanceTest{
    public InstanceTest(){
        System.out.println("实例变量");
    }
}
class StaticTest{
    public StaticTest(){
        System.out.println("静态变量");
    }
}
class A{
    private InstanceTest a = new InstanceTest();
    private  static StaticTest b = new StaticTest();
   static {
       //静态块 -> 专门用来初始化 静态变量
       System.out.println("静态块");
   }
    {
        //实例块 -> 专门用来初始化 实例变量
        System.out.println("实例块");
    }
    public A(){
        System.out.println("构造函数");
    }
}
public class TestDemo {
    public static void main(String[] args) {
        A a = new A();
    }
}

测试结果:
在这里插入图片描述

单例模式

  • 特点:只能有一个实例、 必须自己创建自己的唯一实例、必须向其他对象提供这一实例,单例模式的构造函数必须私有,提供一个共有静态函数,返回实例对象。

  • 懒汉单例模式
    在这里插入图片描述

  • 饿汉单例模式
    在这里插入图片描述

  • 使用场景:
    需要频繁的进行创建和销毁的对象、创建对象时耗时过多耗费资源过多,但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)。

类加载过程

类加载时机
  1. 创建类的实例(new)
  2. 访问某个类或接口的静态变量,或者对该静态变量赋值(static)
  3. 反射 (如Class.forName(“com.shengsiyuan.Test”))
  4. main函数所在的类优先被加载
  5. 先初始化父类,再初始化子类
    子类的初始化顺序
    父类静态变量 -> 父类静态块 -> 子类静态变量 -> 子类静态块 -> 父类实例变量 -> 父类实例块 -> 构造 -> 子类实例变量 -> 子类实例块 -> 构造
类加载过程
  • 第一大阶段:装载阶段
    加载产物:Class对象(保存当前类的所有信息)
    类加载器、双亲委派模型:
    在这里插入图片描述
    使用双亲委派模型的优点:避免类的重复加载安全性高
  • 第二大阶段:链接阶段
    1)验证:验证当前字节码格式,版本号等信息
    2)准备:给静态变量开辟内存,并赋类型默认值
    3)解析:符号引用解析为直接引用
  • 第三大阶段:初始化阶段
    给静态变量赋值操作、使用静态代码块为类变量指定初始值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值