Java类和对象进一步学习

Posted xingweikun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java类和对象进一步学习相关的知识,希望对你有一定的参考价值。

成员变量

public class Book {
    private String name;//定义一个String型的成员变量

    public String getName() {//定义一个getName()方法
        int id = 0;//局部变量
        setName("Java");//调用类中其他方法
        return id + this.name;//设置方法返回值
    }

    public void setName(String name) {//定义一个setNmae()方法
        this.name = name;//将参数值赋予类中的成员变量
    }

    public Book getBook() {//返回Book类引用
        return this;
    }
}

成员方法

定义成员方法的语法格式如下:

成员方法

权限修饰符 返回值类型 方法名(参数类型 参数名){
    ...//方法体
    return 返回值;
}

如果一个方法中含有与成员变量同名的局部变量,则方法中对这个变量的访问以局部变量进行。

权限修饰符

privateprotectedpublic
本类可见可见可见
同包其他类或子类不可见可见可见
其他包的类或子类不可见不可见可见

当声明类时不使用修饰符设置类的权限,则这个类预设为包存取范围,即只有一个包中的类可以调用这个类的成员变量或成员方法。

package com.xwk;
class AnyClass {
    public void doString(){
        ...//方法体
    }
}

在上述代码中,由于类的修饰符为默认修饰符,即只有一个包内的其他类和子类可以对该类进行访问,而AnyClass类中的deString()方法却又被设置为public访问权限,即使这样,doString()方法的访问权限依然与AnyClass类的访问权限相同,因为Java语言规定,类的权限设定会约束类成员的权限设定,所以上面代码等同于下面的代码

package com.xwk;
class AnyClass {
    void doString(){
        ...//方法体
    }
}

局部变量

上面定义的Book类中,getName()方法的id变量即为局部变量。实际上方法中的形参也可作为一个局部变量,如在定义setName(String name)方法时,String name这个形参就被看做是局部变量。
局部变量在方法被执行时创建,在方法执行结束时被销毁。局部变量在使用时必须进行赋值操作或被初始化,否则会出现编译错误。

public String getName() {//定义一个getName()方法
        int id = 0;//局部变量
        setName("Java");//调用类中其他方法
        return id + this.name;//设置方法返回值
    }

局部变量的有效范围

局部变量的有效范围从该变量的声明开始到该变量的结束为止。

在相互不嵌套的作用域中可以同时声明两个名称和类型相同的局部变量。

public void doString(String name){
       int id=0;
       for(int i=0;i<10;i++){
           System.out.print(name+String.valueOf(i));
       }
       for(int i=0;i<3;i++){
           System.out.print(i);
       }
    }

在相互嵌套的区域中不可以重复定义相同名称和相同类型的局部变量。

在作用范围外使用局部变量是一个常见的错误,因为在作用范围外没有声明局部变量的代码。

this关键字

public class Book {
    private String name;//定义一个String型的成员变量

    public String getName() {//定义一个getName()方法
        int id = 0;//局部变量
        setName("Java");//调用类中其他方法
        return id + this.name;//设置方法返回值
    }

    public void setName(String name) {//定义一个setNmae()方法
        this.name = name;//将参数值赋予类中的成员变量
    }

    public Book getBook() {//返回Book类引用
        return this;
    }
}

上述代码中,成员变量与setName()方法中的形式参数的名称相同,都为name,那么如何在类中区分使用的是哪一个变量呢?在Java语言中使用this关键字来代表本类对象的引用,this关键字被隐式的用于引用对象的成员变量和方法,在上述代码中,this.name指的就是Book类中的name成员变量,而this.name=name中的第二个name指的是形参name。setName()方法实现的功能就是将形参name的值赋予成员变量name。

this引用的就是本类的一个对象。在局部变量或方法参数覆盖了成员变量时,如上述代码,就要添加this关键字明确引用的是类成员还是局部变量或方法参数。
如果直接写成name=name,那只是把参数name赋值给参数变量本身而已,成员变量name的值没有改变,因为参数name在方法的作用域中覆盖了成员变量name。
this还可以作为方法的返回值。

public Book getBook() {//返回Book类引用
        return this;
    }

在getBook()方法中,方法返回值为Book类,使用 return this这种形式将Book()类的对象进行返回。

类的构造方法

public book(){
	...//构造方法体
}
public:构造方法修饰符
book:构造方法的名称

在构造方法中可以为成员变量赋值,这样当实例化一个本类对象时,相应的成员变量也将被初始化。
如果类中没有明确定义构造方法,编译器会自动创建一个不带参数的默认构造方法(只有在类中没有定义任何构造方法时)。

public class AnyThting {
    public AnyThting(){//定义无参构造方法
        this("this调用有参构造方法");
        System.out.println("无参构造方法");
    }
    public AnyThting(String name){//定义有参构造方法
        System.out.println("有参构造方法");
    }
}

在无参构造方法中可以使用this关键字调用有参的构造方法。但这种方式只可以在无参构造方法的第一句使用。

静态变量、常量和方法

由static关键字修饰的变量、常量和方法被称作静态变量、常量和方法。
静态成员属于类所有,区别于个别对象,可以在本类或其他类中使用类名和"."运算符调用静态成员。

public class StaticTest {
    final static double PI=3.1415;//在类中定义静态常量
    static int id;//在类中定义静态变量
    
    public static void method1(){//在类中定义静态方法
        //do something
    }
    public void method2(){
        System.out.println(StaticTest.PI);//调用静态常量
        System.out.println(StaticTest.id);//调用静态变量
        StaticTest.method1();//调用静态方法
    }
}

//通常不建议用这样的形式,因为这样容易混淆静态成员和非静态成员。
public class StaticTest {
    final static double PI=3.1415;//在类中定义静态常量
    static int id;//在类中定义静态变量

    public static void method1(){//在类中定义静态方法
        //do something
    }
    public void method2(){
        System.out.println(StaticTest.PI);//调用静态常量
        System.out.println(StaticTest.id);//调用静态变量
        StaticTest.method1();//调用静态方法
    }
    public void method3(){
        method2();
        return this;
    }
}

大家会发现return this;报错,这是因为Java对静态方法有两点规定
在静态方法中不可以使用this关键字
在静态方法中不可以直接调用非静态方法

//不能将方法体内的局部变量声明为static
public class example{
	public void method(){
		static int i=0;
	]
}
//如果在执行类时,希望先执行类的初始化动作,可以使用static定义一个静态区域
public class example{
	static{
		//some
	}
}

类的主方法

public static void main(String[] args) {
        //方法体
    }
//主方法是静态的,所以如要直接在主方法中调用其他方法,则该方法必须也是静态的
//主方法没有返回值
//主方法的形参为数组。可使用args.length获取参数的个数
public class TestMain {
    public static void main(String[] args) {//定义主方法
        for(int i=0;i<args.length;i++){//根据参数个数做循环操作
            System.out.println(args[i]);//循环打印参数内容
        }
    }
}

在Run Configrations中设置

运行结果如下

对象

对象的创建

使用new操作符调用构造方法创建对象

Test test=new Test();
Test test=new Test("a");

Test:类名
test:创建Test类对象
new:创建对象操作符
"a":构造方法的参数

每个对象都是相互独立的,在内存中占据独立的内存地址,并且每个对象都具备自己的生命周期,当一个对象的生命周期结束时,对象就变成垃圾。由Java虚拟机自带的垃圾回收机制处理,不能再被使用。

在Java语言中对象和实例事实上可以通用。

下面看一个创建对象的实例

public class CreateObject {
    public CreateObject(){//构造方法
        System.out.println("创建对象");
    }

    public static void main(String[] args) {//主方法
        new CreateObject();//创建对象
    }
}
====================
创建对象

Process finished with exit code 0

在上述例子的主方法中创建对象,创建对象的同时将自动调用构造方法中的代码。

访问对象的属性和行为

public class TransferProperty {
    int i=50;//定义成员变量
    public void call(){//定义成员方法
        System.out.println("调用call()方法");
        for(i=0;i<3;i++){
            System.out.print(i+" ");
            if(i==2){
                System.out.println("\\n");
            }
        }
    }
    public TransferProperty(){//定义构造方法

    }

    public static void main(String[] args) {
        TransferProperty t1=new TransferProperty();//创建一个对象
        TransferProperty t2=new TransferProperty();//创建另一个对象
        t2.i=60;//将类成员变量赋值为60
        //使用第一个对象调用成员变量
        System.out.println("第一个实例对象调用变量i的结果:"+t1.i++);
        t1.call();//使用第一个对象调用类成员方法
        //使用第二个对象调用成员变量
        System.out.println("第二个实例对象调用变量i的结果:"+t2.i);
        t2.call();//使用第二个对象调用类成员方法
    }
}

====================
第一个实例对象调用变量i的结果:50
调用call()方法
0 1 2 

第二个实例对象调用变量i的结果:60
调用call()方法
0 1 2 

内存中t1,t2两个对象的布局(图手画的)

如果希望成员变量不被其中任何一个对象改变,可以使用static关键字
被声明为static的成员变量的值可以被本类或其他类的对象共享。

public class TransferProperty {
    static int i=50;//定义成员变量
    public void call(){//定义成员方法
        System.out.println("调用call()方法");
        for(i=0;i<3;i++){
            System.out.print(i+" ");
            if(i==2){
                System.out.println("\\n");
            }
        }
    }
    public TransferProperty(){//定义构造方法

    }

    public static void main(String[] args) {
        TransferProperty t1=new TransferProperty();//创建一个对象
        TransferProperty t2=new TransferProperty();//创建另一个对象
        t2.i=60;//将类成员变量赋值为60
        //使用第一个对象调用成员变量
        System.out.println("第一个实例对象调用变量i的结果:"+t1.i++);
        t1.call();//使用第一个对象调用类成员方法
        //使用第二个对象调用成员变量
        System.out.println("第二个实例对象调用变量i的结果:"+t2.i);
        t2.call();//使用第二个对象调用类成员方法
    }
}
====================
第一个实例对象调用变量i的结果:60
调用call()方法
0 1 2 

第二个实例对象调用变量i的结果:3
调用call()方法
0 1 2 

由于t2.i=60语句改变了静态成员变量的值,使用对象t1调用成员变量的值也为60,这正是i值被定义为静态成员变量的效果,即使使用两个对象对同一个静态成员变量进行操作,依然可以改变静态成员变量的值,因为在内存中两个对象同时指向同一块内存区域。
t1.i++语句执行完毕后,i值变为3。当再次调用call()方法时又被重新赋值为0,做循环打印操作。

对象的引用

类名 对象引用名称
一个Book()类的引用
Book book;
引用与对象相关联语法如下:
Book book=new Book();

对象的比较

public class Compare {
    public static void main(String[] args) {
        String c1=new String("abc");
        String c2=new String("abc");
        String c3=c1;
        System.out.println("c2==c3运算结果为:"+(c2==c3));
        System.out.println("c2.equals(c3)运算结果为:"+c2.equals(c3));
    }
}

c2==c3运算结果为:false
c2.equals(c3)运算结果为:true
==运算符比较的是两个对象引用的地址是否相等
equals()比较两个对象引用所指的内容是否相等

嘿嘿,这次我用Visio绘图。

对象的销毁

每个对象都有生命周期,当对象的生命周期结束时,分配给该对象的内存地址需要被回收。在其他语言中,需要用户手动回收废弃对象。Java拥有一套完整的垃圾回收机制,用户不必担心废弃的对象占用内存,垃圾回收器会自动回收无用而却占用内存的资源。

何种对象会被Java虚拟机视为“垃圾”?

对象引用超过其作用范围

..........作用范围
{
	Example e=new Example();
}
..........作用范围
对象e超过其作用范围将消亡

将对象赋值为null

{
	Example e=new Example();
	e=null;
}
当对象被置为null值时,将消亡。

虽然垃圾回收机制已经很完善,但垃圾回收器只能回收那些由new操作符创建的对象。某些对象不是通过new操作符在内存中获取存储空间的,这种对象无法被垃圾回收机制所识别。在Java中提供了一个finalize()方法,这个方法是Object类的方法,它被声明为protected,用户可以在自己的类中定义这个方法。如果用户在类中定义了finalize()方法,在垃圾回收时会首先调用该方法,在下一次垃圾回收动作发生时,才真正回收被对象占用的内存。

垃圾回收或finalize()方法并不保证一定会发生。如果Java虚拟机内存损耗殆尽,它将不会执行垃圾回收处理。

由于垃圾回收不受人为控制,具体执行时间也不确定,所以finalize()方法也就无法执行。为此,Java提供了System.dc()方法来强制启动垃圾回收器 ,主动告知垃圾回收器来进行清理。

以上是关于Java类和对象进一步学习的主要内容,如果未能解决你的问题,请参考以下文章

java基础学习总结--面向对象

Java创建对象的过程

05-JAVA类和对象

JAVA方法的定义

JAVA编程中的类和对象

从零开始的 Java 学习类和对象的认识