Java中的类和对象

学习目标

本讲主要介绍如何在Java中设计和使用类的基础知识,包括:
类的初始化方法,
“==”的含义,
this的用法,
装箱与拆箱,
……
其中,理解对象变量的含义是关键。
本讲还介绍了javap反汇编.class文件的基本方法。 在课堂上会引导大家阅读Java字节码指令。
本讲属于Java面向对象编程最为基础的内容,必须牢固掌握。

编写类的“模版”

public/private class 类名
{
     public/private 数据类型 变量名;
     public/private 数据类型 方法名(参数列表){}  
}

两种最基本的存储权限:
public:存储和访问不受限制
private:除非是属于类自己的方法,外界代码不能存取和访问

定义Java类的示例

某些编程语言比如(C#)为“属性”(property)提供了单独的定义方式,在Java中我们可以通过组合一个私有字段和一对get/set方法来定一个属性。

class Myclass{
public String Information="";
pubic void myMethod(String argu)
{
       System.out.println(argu);
}
private int value;
public int getValue()
{
return value;
}
public void setValue(int value)
{
this.value=value;
}
使用自定义类

在这里插入图片描述

小结

  • 我们需要定义一个对象变量
  • 然后“创建new”一个对象,赋值给对象变量
  • 现在就可以通过对象变量使用对象,主要方式有:
    直接调用类的方法/存取类的字段

一种新的变量类型

通过对int value = 100;Myclass obj = new Myclass();两种方式定义变量,这两种方式定义的变量是一样的吗?
引用类型vs原始数据类型

  • “引用”一个对象的变量称为“引用类型”的变量,即对象变量
  • int、float之类的称为原始数据类型
变量与内存分配
  • 当声明一个对象变量时没有马上创建一个对象,此变量=null
  • 定义一个原始类型的变量,马上给其分配内存空间
    在这里插入图片描述
    在这里插入图片描述
变量的初始化

Java定义变量时,要求必须显式初始化变量。

int value;
system.out.println(value);//wrong
int value=100;
system.out.println(value);//correct
对象变量的初始化

对象变量如果不引用一个真实的对象,则必须声明为null

Myclass obj;
system.out.println(obj.toString());//wrong 
Myclass obj=null;
system.out.println(obj.toString());//correct

对象变量的特殊值null:代表一个对象变量不引用任何对象

引用对象后的对象变量
Myclass obj = new Myclass();


当对象不再使用时,JVM会回收Myclass对象所占用的内存,这个过程称为==“垃圾回收(GC:garbage collection)”==

理解赋值的含义

myclass obj1 = new myclass();
myclass obj2 = obj1;

在这里插入图片描述

独特的对象引用:this
  • 对象中的所有数据字段都是通过this指针间接引用的
    在这里插入图片描述
  • 同一类中的方法可以相互调用,或者直接存取本类定义的字段,可以看成是其中隐含了一个this引用
    在这里插入图片描述
作为常量的对象变量
  • 可以使用final定义一个”常量“对象变量final myclass obj = new Myclass();
  • ⚠️:”常量“对象变量不能指向另一个对象,但可以修改对象所包容的数据,比如设置它所引用对象的某个公有字段值
对象判等
  • 对于原始数据类型的变量(比如int),可以直接使用“==”判等来判断变量值是否相等
    在这里插入图片描述
  • 当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等
  • 当“==”施加于引用类型变量时,是比较这两个变量是否引用同一个对象
  • 引用代表地址,所以“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同
    在这里插入图片描述
    比较两个对象相等的标准
  • 两个对象的“内容”,其实是指它们在某一段时刻的所有字段的值,“内容相等”,其实就是”对应字段值“一致
  • 方法:重写(override)基类的equals()方法
class myclass
{
    public int value;
    @Override
    //这种写法说明此方法是“重写基类的同名方法”,Java中,这种以“@”打头的标记被称为“Annotation”
    public boolean equals (Object obj)
    { return ((myclass) obj).value == this.value; }
    //传入参数是Object类,所以这里有个类型转换
    //这种override方式是简化的,在实际开发中不应该这样写,应该加上对参数有效性的检测代码
    public myclass(int initvalue)
    {value=this.initvalue;}
}

equals()方法从哪来?

  • 当定义一个类时,如果不显示指明它的“父类”是哪个,默认时Object
    也就是说当前自定义的类会继承Object类的所有方法
  • Object是Java的最顶层基类,其中定义了equals()方法
    object类的成员 在这里插入图片描述
自定义equals()方法
  • 除了重写基类的equals方法,也可以“重载”(overload)equals()方法
class myclass{
     public int value;
     public boolean equals(myclass obj)
     {
     return obj.value == this.value;
     }
     //与前面“重写”方式的代码相比,equals()方法的参数类型是myclass而不是object
     //并且方法本身也没有附加@override标记
     public myclass(int initvalue)
     {value = initvalue;}
}
类的构造方法
  • consturctor构造方法/构造函数
  • 当创建一个对象时,它的构造方法会自动调用
  • 构造方法与类名相同,没有返回值
  • 如果类没有定义构造函数,Java编译器在编译时会自动给它提供一个没有参数的“默认构造方法”
  • 如果自定义构造方法之后,编译器提供的默认方法失效
  • 多构造函数
    同一个类可以有多个构造函数,多个构造函数之间通过参数来区分,这是方法重载的一个实例
    同一个类的构造函数之间可以通过this关键字相互调用
class fruit{
int grams;
int calspergram;
fruit(){
this(55,10);
}
Fruit(int g,int c){
grams=g;
calspergram=c;
}
}
类的初始化块
  • 可以在类中使用{}将语句包围起来,直接将其作为类的成员,成为类的初始化块
  • 类的这种没有名字的成员,多用于初始化类的字段
  • 在实际开发中应该尽量保证一个字段只初始化一次
类字段初始化顺序
  1. 执行类成员定义时指定的默认值或类的初始化块,由书写代码时哪个代码排在后面,就执行哪个
  2. 执行类的构造函数
  3. 类的初始化块不接收任何的参数,只要一创建类的对象,它们就会被执行。因此,适合于封装那些对象创建时必须执行的代码
  4. 当多个类之间有继承关系时,创建子类对象会导致父类初始化块的执行
//父类
class test
{
	{
		value=100;
		System.out.println("这是父类的初始化块");
	}
	public int value;
	public test(int value)
	{
		this.value=value;		
	}
	public test()
	{
		System.out.println("这是父类的构造函数");
	}
}
//子类
class subtest extends test
{
	{
		subvalue = 200;
		System.out.println("这是子类的初始化块");		
	}
	public int subvalue;
	public subtest()
	{
		System.out.println("这是子类的构造函数");
	}
}
//测试部分
public class welcome1{
	public static void main(String args[]) {
       subtest t = new subtest();  
	}	
}

结果

这是父类的初始化块
这是父类的构造函数
这是子类的初始化块
这是子类的构造函数
类的静态字段
class test
{
static int value;
}
  • 可以用对象名或类名作为前缀访问静态数据/方法(实际开发用类名
test t = new test();
t.value=1;
test.value=1;
类的静态初始化块
  • 可以使用”静态初始化块“初始化类的静态字段
public class test
{
public static int value;
static{
value=100;
}//类的静态初始化块
}

静态初始化块、初始化块、构造方法三者的顺序
class test
{
	{
		value=100;
		System.out.println("这是父类的初始化块");
	}
	static
	{
		value1=200;
		System.out.println("这是父类的静态初始化块");
	}
	public int value;
    public static int value1;
	public test(int value)
	{
		this.value=value;		
	}
	public test()
	{
		System.out.println("这是父类的构造函数");
	}
}
class subtest extends test
{
	{
		subvalue = 200;
		System.out.println("这是子类的初始化块");		
	}
	static {
		subvalue1=200;
		System.out.println("这是子类的静态初始化块");
	}
	public int subvalue;
	public static int subvalue1;
	public subtest()
	{
		System.out.println("这是子类的构造函数");
	}
}
public class welcome1{
	public static void main(String args[]) {
		System.out.println("第一次调用:");
       subtest t = new subtest();
       System.out.println("第二次调用:");
       subtest t1 = new subtest();	   
	}	
}

结果

第一次调用:
这是父类的静态初始化块
这是子类的静态初始化块
这是父类的初始化块
这是父类的构造函数
这是子类的初始化块
这是子类的构造函数
第二次调用:
这是父类的初始化块
这是父类的构造函数
这是子类的初始化块
这是子类的构造函数

总结

  1. 静态初始化块只执行一次,且父类的先执行,然后是子类的静态初始化块
  2. 然后是父类的初始化块、父类的构造函数
  3. 最后是子类的初始化块、子类的构造函数
  4. 创建子类对象时父类的静态初始化块、初始化块、构造函数都执行
类的静态方法

类的静态方法只能访问类的静态成员!!!!!!

class test{
int value;
static int value1;
static void clear(){
value1=0;
}//类的静态方法只能访问类的静态成员
}

An interesting question?

如何在静态方法里访问类的实例成员(即没有static关键字修饰的字段或方法)?

//自己做的时候在static里面new了一个对象,然后通过对象变量来访问非static成员
//其实也可以传参使用
//其实想到static出现的原因是因为有些函数本身存在的意义就是全局的,只不过是为了满足Java面向对象的需求,才不得不依附于类,所以就正常把它看成一个全局函数就好
//其实从public static void main()就可以看出来,在main函数里是可以随意创建对象的
class test
{
	private int value;
	public test(int i) {
		value = 1;
	}
	public void showresult()
	{
        System.out.println("This is not static method!");
	}	
	static void staticmethod()
	{
		System.out.println("This is a static method!");	
	    test t = new test(1);
	    t.showresult();
	    t.value=2;
	    System.out.println("This is a static variable:"+t.value);	   
	}
}
public class welcome1{
	public static void main(String args[]) {
	   test.staticmethod();   
	}	
}

static方法是在编译的时候确定的,在类装入内存的时候也装入内存了;非static方法是在实例化的时候装入内存的。

包装类

  • 基本数据类型仅仅提供了数据,却缺少一些常用的功能,为此,Java提供了包装类
    包装类=基本数据类型的数据+扩充的一些方法和字段
  • 包装类是引用类型,可以创建相应的对象
    在这里插入图片描述
使用包装类

在这里插入图片描述

Integer obj = new Integer(1);
int value = obj.intValue();
装箱和拆箱

BoxAndUnbox

int value = 100;
Integer obj = value;
int result = obj*2;

查看字节码的方法

  1. javap反汇编指令(终端)
    反汇编工具javap的参数说明
    在这里插入图片描述
  2. 使用反汇编工具jClasslib来分析生成的class文件

在这里插入图片描述
第一题:

class test
{
    static int count=0;
	static {
	  count=0;
	}
	public test()
	{
		count++;
	}
    static int returnCreateNumber()
    {
      return count;
    }
}
public class welcome1{
		public static void main(String args[]) {
	  test t = new test();
	  test t1= new test();
	  System.out.println(test.returnCreateNumber());
	  test t2 = new test();
	  System.out.println(test.returnCreateNumber());
	  test t3 = new test();
	  test t4= new test();
	  System.out.println(test.returnCreateNumber());
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值