JavaSE-类与对象1

1.类与对象的定义与使用

① 类与对象的概念

    所谓类,是一个共性的概念,而对象指的是一个具体的、可以使用的事物。

    首先产生类(类是生产对象的蓝图),而后才可以产生对象,对象的所有行为一定在类中进行了完整的定义。

类的组成:

1.属性(变量,描述每个对象的具体特点)

2.方法(操作的行为)

② 类与对象的定义与使用

  • 定义一个类

语法如下:

class 类名称{

    属性1;

    属性2;

    ...

    属性n;

    方法1(){};

    方法2(){};

    ...

    方法n(){};

}

注意:此时的方法不再由主类直接调用,而是由该类的实例化对象进行调用

类对象实例化语法:

类名称 类对象名称 = new 类名称();

示例:定义一个Person类并实例化类对象

class Person{
    public String name;
    public int age;
    public Person(String n,int a){
        name = n;
        age = a;
    }
    public void getPersonInfo(){
        System.out.println("姓名:" + name + ",年龄" + age);
    }
}
public class Test{
    Person p1 = new Person("李四",19);//直接通过构造函数实例化
    Person p2 = new Person();
    //通过对象修改类属性、调用类方法
    p2.name = "张三";
    p2.age = 18;
    p1.getPersonInfo();
    p2.getPersonInfo();
}

注意:只要出现了关键字new,就开辟了内存空间;

          Java中,所谓的性能调优,调整的就是内存问题。

③ 对象内存分析

       栈内存(虚拟机局部变量表):存放局部变量(包含编译期可知的各种基本数据类型,对象引用-即堆内存地址,可以简单理解为对象的名称)。

      Java栈是与线程对应起来的,每当创建一个线程,JVM就会为这个线程创建一个对应的Java栈。

      堆内存:保存真正的数据。即对象的属性信息。

代码示例:

class Person{
    String name;
    int age;
}
public class Test{
    public static void main(String[] args){
        Person per = new Person(); 
        per.name = "张三";
        per.age = 30;
    }
}

对于主函数中的第一条语句:Person per = new Person();//在堆上分配内存并产生Person类的对象per引用这部分内存。

内存分析如下:

接下来两句:

  per.name = "张三";
  per.age = 30;

内存图分析如下:

注意:对象必须在实例化之后调用,否则会产生NullPointerExecption(运行时错误),编译时不会出错;

        只有引用类型(数组、类、接口)才会产生此类异常,因此在后续写代码过程中如果出现此类异常,就可以根据出错位置查看引用数据类型是否初始化。

④ 引用传递分析

本质:一块堆内存可以被多个栈内存所指向

代码示例:

Person p1 = new Person();
Person p2 = new Person();
p2 = p1;

内存分析图如下:

    垃圾空间:没有任何栈内存指向的堆内存空间

    所有的垃圾空间会不定期GC,GC不会影响性能,所以在开发中一定要控制好对象的产生数量(无用的对象尽可能少产生)

2.private实现封装处理&构造方法(匿名对象)

① private实现封装处理

    以上所写的所有程序都属于无封装程序。

    在不进行封装的情况下,在主类中可以任意对Person类的对象属性进行修改。此时,要回避此类问题,让类内部操作堆外部不可见(对象不能直接操作属性),可以使用private进行封装。

示例:在Person类中使用private封装属性

private String name;
private int age;

    此时使用private堆属性进行了封装,要访问私有属性,按照Java的设计原则必须在类中提供以下两种方法:

1.getter方法:主要用于进行属性内容的设置和修改

2.getter方法:主要用于属性内容的取得

示例:扩展Person类中的方法,实现对Person类属性的封装

class Person{
    private String name;
    private int age;
    public void setName(String a){
        name = n;
    }
    public String getName(){
        return name;
    }
    public void setAge(int i){
        if(i > 0 && i <= 100){
            age = i;
        }else{
            age = 0;
        }
    }
    public int getAge(){
        return  age;
    }
    public void getPersonInfo(){
        return "姓名:"+name+",年龄:"+age;
    }
}
public class Test{
    public static void main(String[] args){
        Person p = new Person();
        p.setName("张三");
        p.setAge(18);
        p.getPersonInfo();
    }
}

    通过以上代码我么可以发现,private实现封装的最大特征在于:只允许本类访问,而不允许外部类访问。

  • 类的设计原则:

      1)在编写类时,类中的所有属性必须使用private封装

      2)属性若要被外部访问,必须定义setter、getter方法。

②构造方法与匿名对象

回顾产生对象的方法:

①类名称 ②对象名称 = ③new ④类名称();

  • ① 任何对象都有对应的类,类时对象的蓝图 ;

  • ② 对象名称是一个唯一的标记,引用一块堆内存;

  • ③ new表示开辟新的堆内存空间;

  • ④ 构造方法

通过上述分析可知,所谓的构造方法就是使用关键字new实例化新对象来进行调用的操作方法。对于构造方法的定义,也需要遵循以下原则:

1.方法名必须与类名称相同;

2.构造方法没有返回值类型声明;

3.每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)

问题:构造方法无返回值,为什么没有void声明?

   首先我们先来看一下类的组成:属性、构造方法、普通方法

1.属性是在对象开辟堆内存时开辟的空间;

2.构造方法是在使用new后调用的;

3.普通方法是在空间开辟了,构造方法执行之后可以多次调用的。

   部分代码示例:

public void Person(){} //命名不标准的普通方法
public Person(){}    //无参构造方法

         从以上描述我们可以看出,编译器是根据程序结构来区分普通方法和构造方法的,所以在构造方法前没有返回值类型声明。

        若类中定义了构造方法,则默认的无参构造将不再生成。

示例:使用构造方法设置对象属性

class Person{
    private String name;
    private int age;
    public Person(String n,int a){
        name = n;
        age = a;
    }    
    public void setName(String n){
        name = n ;
    }
    public String getName(){
        return name;
    }
    public void setAge(int i){
        if (i>0&&i<=200) {
            age = i ;
        }else {
            age = 0 ;
        }
    }
    public int getAge(){
        return age;
    }
    public void getPersonInfo(){
        System.out.println("姓名:"+name+",年龄:"+age);
    }
}
public class Test{
    public static void main(String[] args) {
        Person person = new Person("张三",-200);//使用构造函数对对象属性进行赋值
        person.getPersonInfo();
    }
}

       构造方法的调用和对象内存分配几乎是同步完成的,因此我们可以利用构造方法来为类中的属性进行初始化操作(可以避免多次的setter调用)

构造方法重载:参数类型或个数不同

示例:

public Person(){

    System.out.println("---无参构造---");    

}

public Person(String n){

    name = n;

    System.out.println("---有参构造---");

}

建议:若干构造方法,最好按照参数个数升序或降序编写;

          在进行类定义时:①定义属性-->②定义构造方法-->③定义普通方法

范例:匿名对象

new Person("张三",20).getPersonInfo();

注意:由于匿名对象不会有任何的栈空间指向,所以使用一次后就成为垃圾空间。

3.this关键字

① 用途

    ⅰthis调用本类属性

    ⅱ this调用本类方法

    ⅲ this表示当前对象

② this调用本类属性

代码示例:不用this关键字时

class Person{
    private String name;
    private int age;
    public Person(String name,int age){
        name = name ;
        age = age ;
    }
    public String getPersonInfo(){
        return "姓名:" + name + ",年龄:"+age;
    }
}
public class Test{
    public static void main(String[] args) {
        Person per = new Person("张三",20);
        System.out.println(per.getPersonInfo());
    }
}

      通过上述代码我们可以发现:当参数与类中属性同名时,类中属性无法被正确赋值。此时若加上this关键字就可以解决这个问题。

示例:使用this关键字修改上述代码

public Person(String name,int age){
    this.name = name;
    this.age = age;
}

为了避免类似问题,只要在类中方法访问类中属性,一定要加this关键字。

②this调用本类方法

this调用本类方法有两种情况:

    ⅰ调用普通方法:this.方法名称(参数);

    ⅱ 调用构造方法:this(参数);

示例:this调用普通方法

class Person{
    private String name;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this,age = age;
        this.print(); //this调用普通方法
    }
    public String getPersonInfo(){
    return "姓名:" + name + ",年龄:"+age;
  }
  public void print(){
    System.out.println("*****************");
  }
}
public class Test{
    public static void main(String[] args) {
        Person per = new Person("张三",20);
        System.out.println(per.getPersonInfo());
    }
}

示例:多个构造函数同时存在

class Person{
    private String name;
    private int age;
    public Person(){
        System.out.println("********产生一个新的Person对象********");
    }
    public Person(String name){
        System.out.println("********产生一个新的Person对象********");
        this.name = name ;
    }
    public Person(String name,int age){
        System.out.println("********产生一个新的Person对象********");
        this.name = name ;
        this.age = age ;
    }
    public String getPersonInfo(){
        return "姓名:" + name + ",年龄:"+age;
    }
}
public class Test{
    public static void main(String[] args) {
        Person per1 = new Person();
        Person per2 = new Person("张三");
        Person per3 = new Person("李四",20);
        System.out.println(per1.getPersonInfo());
        System.out.println(per2.getPersonInfo());
        System.out.println(per3.getPersonInfo());
    }
}

Java中支持构造函数的相互调用

示例:this调用构造函数(上述代码的修改)

public Person(){
    System.out.println("---产生一个新的Person对象---");
}
public Person(String name){
    this();//调用本类无参构造
    this.name = name;
}
public  Person(String name,int age){
    this(name);//调用本类有参构造
    this.age = age;
}
  • 使用this调用构造方法时应注意:

1.this调用构造方法的语句必须放在构造方法首行;

2.使用this调用构造方法时,必须留有出口(即不能成环)

④ 使用this表示当前对象

示例:

class Person{
    public void print(){
        System.out.println("[PRINT]方法:"+this);
    }
}
public class Test{
    public static void main(String[] args) {
        Person p1 = new Person();
        System.out.println("[MAIN]方法:"+p1);
        p1.print();
        System.out.println("=================");
        Person p2 = new Person();
        System.out.println("[MAIN]方法:"+p2);
        p2.print();
    }
}

    只要对象调用了本类中的方法,这个this就表示当前执行的对象。

5.static关键字

static可以修饰属性和方法

① static属性(类属性)

示例:实例属性的内存分析

class Person{
    String Country = "中国";
    String name;
    int age;
    public void getPersonInfo(){
        System.out.println("姓名:"+this.name+",年龄:"+this.age+",国家:"+this.Country);
    }
}
public class Test{
    public static void main(String[] args){
        Person p1 = new Person();
        p1.name = "张三";
        p1.age = 19;
        Person p2 = newPerson();
        p2.name = "李四";
        p2.age = 20;
        p1.getPersonInfo();
        p2.getPersonInfo();
        
    }    
}

内存图解:

    传统属性所具备的特征:保存在堆内存中,且每个对象独享属性。

    描述共享属性,只需要再属性前添加static关键字即可。

    static属性又称为类属性,保存在全局数据区的内存之中,所有对象都可以进行该数据区的访问。

若修改上述代码堆country的定义为:

static String Country = "中国";

此时内存分析图如下:

结论:

1.访问static属性(类属性)应使用类名称.属性名

2.所有非static属性(实例变量)必须在对象实例化后使用,而static属性(类属性)不受对象实例化控制。

此时,如果我们修改country属性,所有对象都同步此值

定义类时,如何选择实例变量和类属性变量?

1.定义类时,一般情况下不会考虑static属性,以非static属性为主

2.如果需要描述共享属性的概念,或者不受对象实例化的控制,使用static

② static方法(类方法)

使用static定义的方法,直接通过类名访问

示例:

class Person{
    private static String country;
    private String name;
    private int age;
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    public static void setCountry(String c){
        country = c;
    }
    public void getPersonInfo(){
        System.out.println("姓名:"+this.name+",年龄:"+this.age+",国家:"+this.country);
    }
}
public class Test{
    public static void main(){
        Person.setCountry("中国");
        Person person = new Person("张三",18);
        person.getPersonInfo();
    }
}

注意:

    (1)所有static方法不允许调用非static定义的属性或方法;

    (2)所有的非static方法允许访问static方法或属性。

使用static定义方法的目的:某些方法不希望受类的控制,即可以在没有实例化对象的时候执行(广泛存在于工具类中)

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值