Java对象和类

对象和类的学习

对对象的理解:

在现实生活中,每一个具现化的物体都可以看作一个对象,每一个抽象的方法,数据等也可以看作对象。在计算机中,比如每一个按钮,每一个图标,都可以看作一个对象。每个对象都有自己独特的标识、状态和行为,例如对于按钮,大小,形状颜色等就是它的状态,在java中被称为状态state(亦称为特征property或属性attribute)。

对类的理解:

Java中的类即为同一类型对象(拥有相同或者类似的标识、状态和行为的对象)的集合。拿生活来类比的话,静态的事物中,拥有不同大小的圆可以归为一类,不同大小的矩形可以归为一类;动态的事物中,有相同行为或者相同状态的可以归为一类,例如一些都在奔跑,一些都坐着等等。


类中有实例数据域,实例方法,构造方法和静态方法。


创建类、实例、实例数据域、构造方法、实例方法:

class SimpleRectangle{

    double length = 1;

    double width = 1;//两个均为实例数据域

    SimpleRectangle(){

};//此处SimpleRectangle()为构造方法,用于构造一个属于该类的对象。该对象默认拥有length值为1,width值为1。

    SimpleRectangle(double newlength, double newwidth){

    length = newlength;

    width = newwidth;//此处SimpleRectangle()同样为构造方法,用于构造一个属于该类的对象,该对象需要输入长和宽。

}

    double getArea(){

    return length * width;//实例方法

}

}

实例:

SimpleRectangle rectangle1 = new SimpleRectangle();

创建方法与创建数组类似。分为两步:

首先ClassName objectRefVar声明对象的引用变量(reference variable,对于引用变量的理解可参考C中的指针).

再用new ClassName(arguments)创建实例对象。

ClassName objectRefVar = new objectRefVar(arguments);

也可以直接使用new ClassName(arguments)创建一个实例对象,该对象没有相应的引用变量,被称为匿名对象。

类是一个抽象的定义,而实例就是该种抽象的具象。创建实例的过程被称为实例化

实例数据域:

对于没有参数的构造方法建立的实例,它的数据域即为默认的数据域。在该例中即为length = 1 和 width = 1。

对于有参数的构造方法建立的实例,它的数据域即为传入数据。在该例中,若用

SimplereRtangle rectangle2 = new SimpleRectangle(2, 2);

建立一个引用变量为rectangle2的实例,则该实例的数据域为length = 2, width =2。

构造方法:

使用方法:

new ClassName(arguments);

特殊的方法:

1、构造方法的名字必须与类名相同。例如在此处类名为SimpleRectangle,则构造方法名也必须为SimpleRectangle。

2、构造方法没有返回值类型,连void也没有。

3、构造方法只有在建立一个对象实例时被调用。

构造方法的作用其实就是初始化一个对象。

与所有的其他方法一样,构造方法也可以重载。例如该例中

SimpleRectangle(){
};//无参构造法
SimpleRectangle(double newlength, double newwidth){
length = newlength;
widht = newwidth;
};//有参构造法

可以有同名的构造方法,但是签名必须不同。

一个类也可以不定义构造方法,在这种情况下类中会隐含定义一个方法体为空的无参构造方法,被称为默认构造方法(default constructor),当且仅当类中没有明确定义任何构造方法时才会自动提供它。

实例方法:

在该类中定义并且修饰符中没有静态修饰符static的即为实例方法。

实例方法依赖于实例。例如getArea()方法,依赖于某个具体的矩形(必须要有一个具体矩形的数据才能进行计算) 。

如何访问实例数据域,调用实例方法:

运用点操作符(.)通过引用变量进行访问。

double length = rectangle1.length;//将rectangle1的长度赋值给定义的变量length.

在此处引用了数据域,若在类中length和width被定义但未被赋值,对于该类数值型数据域,则默认为0;对于引用类型变量例如String,未被赋值时默认为null;对于boolean类型数据域,默认值为false;对于char类型数据域,默认值为"\u0000"。

double AreaOfRectangle1 = rectangle1.getArea();//调用实例方法getArea(),计算rectangle1的面积,并返回给变量AreaOfRectangle1。


静态变量和静态方法:

如何区别:变量名和方法名前加了静态修饰符static的即为静态变量或静态方法。

static numberOfObjects;
static int getNumberObjects(){
    return numberOfObjects;
}

静态变量:不同于实例数据域,实例数据域专属于某个特殊的对象,例如初始设定的length和width专属于对象rectangle1,静态变量属于整个类中的所有对象,被类中的所有对象共享。

如何理解静态变量被类中的所有对象共享:

举例:

public class Welcome {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		T t1 = new T();
		T t2 = new T();
		System.out.println("t1's i = " + t1.i + " and j = " + t1.j + " and q = " + t1.q);
		System.out.println("t1's i = " + t2.i + " and j = " + t2.j + " and q = " + t2.q);
	}
}
	class T{
		static int i = 0;
		int j = 0;
		int q = 0;
		T(){
			i++;
			j = 1;
			q--;
		}
}
该程序最后输出为:t1's i = 2 and j = 1 and q = -1

                              t1's i = 2 and j = 1 and q = -1

原因:

i为static修饰符修饰的静态数据,在创建t1时i变为1,在创建t2时i变为2,因为静态变量是被类中所有对象共享的,所以最后输出时t1.i也为2,也因为i为静态变量,所以正确的访问i的方法应该为T.i,通过类访问,而不是通过对象访问;

j和q为普通实例数据,所以是实例所私有的,因此最后输出时q并不是-2而是-1。


静态方法:同理与静态变量与实例数据的关系,实例方法属于某个对象,因此实例方法必须先创建实例对象才能调用,静态方法无须创建类的实例也可调用(调用方法:ClassName.methodName。虽然也可以使用ObjectName.methodName来调用静态方法,但因为只有静态方法可以使用ClassName.methodName的方法来调用,使用该种方法调用可以提高可读性,可以一眼就看出哪个方法是静态方法,所以建议使用ClassName.methodName来调用静态方法)。

静态成员和实例成员的关系总结:

 实例方法实例数据域静态方法静态数据域
实例方法可调用可访问可调用可访问
静态方法不可调用不可访问可调用可访问

用实际例子解释这份总结:

public class A{

    int i = 5;

    static int k = 2;

    public static void main(String[] args){

        int j = i;//i是实例数据,必须要使用具体对象来访问。

        m1();//m1是一个实例方法,必须要使用具体对象来调用。

    }

    public void m1(){

        i = i + k + m3(i, k);//实例方法m1调用静态方法m3。
        m2();//实例方法m1调用实例方法m2,不需要依赖于某个实例。
    }
    public void m2(){
        System.out.print("Wwy is the cuttest");
    }

    public static int m3(int i, int j){

        return (int)(Math.pow(i, j));

    }

}

正确应该为:

public class A{

    int i = 5;

    static int k = 2;

    public static void main(String[] args){
        A a = new A();//因为类A中没有明确定义的构造方法,所以此处用了默认构造方法。
        
        int j = a.i;//i是实例数据,必须要使用具体对象来访问。

        a.m1();//m1是一个实例方法,必须要使用具体对象来调用。

    }

    public void m1(){

        i = i + k + m3(i, k);//实例方法m1调用静态方法m3。
        m2();//实例方法m1调用实例方法m2,不需要依赖于某个实例。

    }
    public void m2(){
        System.out.print("Wwy is the cuttest");
    }

    public static int m3(int i, int j){

        return (int)(Math.pow(i, j));

    }

}


关于修饰符

类、方法和数据域均有四种修饰符,分别为:public,private,protected和不加修饰符。

public修饰符代表类、方法和数据域可以被任意其他类访问;

private修饰符代表类、方法和数据域只能被自己所在的类访问;

protected修饰符之后补充;

不加修饰符代表类、方法和数据域能被同一个包内的任意一个类访问。

数据域封装

为了避免对数据的直接修改,用private修饰符将数据域声明为私有的,这称为数据域封装

因为加了private修饰符,因此在客户端(调用该类的程序被成为该类的客户)无法直接访问和修改数据域,但有时又会存在需要访问数据域的情况,此时我们可以建立一个get方法返回数据域的值,建立一个set方法修改数据域的值。get方法被称为访问器(accessor),set方法被称为修改器(mutator)。

get方法签名:

public retrunType getPropertyName()

若返回值类型为boolean型,则习惯上用如下方法定义:

public boolean isPropertyName()

set方法签名:

public void setPropertyName(dataType propertyValue)


将对象作为参数传入方法:

1、传入的是对象的引用。

2、静态方法在接收一个引用变量时,并不是直接对该引用变量指向的对象进行操作的,而是会先制造一个副本,然后对该副本进行操作。

例:

public class Welcome {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Date date = null;
		m1(date);
		System.out.println(date);
	}
	public static void m1(Date date) {
		date = new Date();
	}
}

在该例中,按照理论:将对象传入方法时传入的是引用变量,因此方法中的修改会影响到方法外的修改。

最后输出的结果应该m1方法中建立的对象,输出程序运行时的当前时间。但事实输出的是null。

原因:在将对象date传入静态方法m1时,会自动建立一个副本,这里假定这个副本的名字为date1,此时两个引用变量date和date1均指向date对象null。方法所进行的操作date = new Date()实际是对date1进行的,因此date依然指向null,但date1却指向了新对象new Date(),所以date所指向对象并未改变,最后输出结果为null。


不可变对象和类:

由不可变类(immutable class)建立的实例就是不可变对象(immutable object)。

满足如下要求的为不可变类:

1、所有数据域都是私有的;

2、没有修改器方法;

3、没有一个返回指向可变数据域的引用的访问器方法。

例如String类就是不可变类。


变量的作用域:

目前接触的变量已经有三种:

局部变量,实例变量和静态变量。其中实例变量和静态变量统称为类变量(class variables)或数据域(date field)。

局部变量:声明和使用都在方法内部。

类变量:无论在何处声明,作用域为整个类。

当局部变量和类变量具有相同的名字时,局部变量优先,类变量被隐藏。

例:

public class F{

    private int x = 0;

    private int y = 0;

    public F(){

    }

    public void p(){

        int x = 1;

        System.out.print("x = " + x + ", " + "y =" + y);

    }

}

最后输出结果为x = 1, y = 0。


this引用:

this引用的作用:

1、引用对象自身;

2、引用隐藏数据域;

3、调用构造方法。

举三个例子对应三种作用:

例1:

public double getArea(){

    return this.radius * this.radius * Math.PI;//Circle类中计算圆的面积。

}
等同于 return radius * radius * Math.PI;//因此该种情况下通常this引用省略。

例2:

class Test{
	private int id;
	public void m1(int id) {
		this.id = id;//因为参数名id与实例变量id同名,因此实例变量id被隐藏,需要用this来引用。
	}
}

例3:

class Circle{
	private double radius;
	public Circle(double radius) {
		this.radius = radius;
	}
	public Circle() {
		this(1.0);//通过this调用构造方法public Cricle(double radius)。
	}
}
当一个类有多个构造方法时,尽可能使用this(参数列表)的方法来实现,通常无参数或少参数的构造方法都可以用this(参数列表)调用参数多的构造方法,这样做可以简化代码,易于阅读和维护。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值