Java对象和类

java作为一种面向对象的语言,是支持多态,继承,封装,抽象,类,对象,实例,方法,重载.

该文章研究对象和类的概念.

  • 对象:对象是类的一个实例(对象不是找个女朋友),有状态和行为。例如,一个人是一个对象,它的状态有:肤色、名字、性别;行为有:睡觉,、说话,吃等。
  • :类是一个模板,它描述一类对象的行为和状态。

下图中男孩女孩为类,而具体的每个人为该类的对象:

java中的对象

什么是对象(object):万物皆对象:对象就是个体

通过上图可以认为人就是对象,像生活中车,动物,植物等,这些都可以认为是对象,而且这些对象都有自己的状态和行为

用车举例,它的状态有,品牌,颜色,行为有,启动,要玻璃窗等

对比现实对象和软件对象,它们之间十分相似。

软件对象也有状态和行为。软件对象的状态就是属性,行为通过方法体现。

在软件开发中,方法操作对象内部状态的改变,对象的相互调用也是通过方法来完成。

Java中的类

类是对象的图纸,模板,

通过下面一个简单的类来理解下Java中类的定义:

public class people{
  String breed;
  int age;
  String color;
  void eating(){
  }
 
  void hungry(){
  }
 
  void sleeping(){
  }
}

一个类可以包含以下类型变量:

  • 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
  • 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
  • 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。

一个类可以拥有多个方法,在上面的例子中:eating()、hungry()和sleeping()都是People类的方法。

类和对象之间的关系

类是对象的图纸,模板.对象是类的实例化

重点在于如何构建这个蓝图,模板

如何去定义一个类,确定类和类之间的关系,下面介绍构造方法

 构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。

在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。

对象新建的过程:Person p = new Person

 

从广义的角度,构造器的作用:初始化:对对象使用之前进行信息的预处理

构造器的定义:

①构造方法的方法名必须与类名保持一致

②构造方法没有返回值类型;构造方法返回的一定对象本体的内存地址

③构造方法仅仅允许使用访问权限修饰符进行修饰

④系统给每一个类都提供一个默认的空构造(没有参数的构造方法),这个构造方法仅仅用来给各个属性赋默认值

⑤默认的控构造只能在没有任何手动定义的构造器的类中使用:如果手动定义了一个构造方法,默认的构造方法就失效

⑥在同一个类中,可以存在多个构造器(构造器的重载)

方法的重载

java中如何区分两个方法

①方法的调用者:方法的调用者一旦确定,就能够根据调用者找到这个方法的归属

②方法名

③方法的形参列表

****注意:方法的返回值并不能用来区分两个方法:一个方法在调用的时候,可以接收返回值也可以不接收,在不接收返回值的时候,就没有办法通过返回值(类型)区分两个同名、相同形参列表、定义在同一个类中的方法

方法的重载定义:两同一不同:在同一个类中,定义多个同名方法,使用不相同的形参列表进行区分

不同的形参列表

  ①形参列表的长度(形参的个数)

  ②形参的类型

  ③形参的顺序

注意:

  • 重载方法参数必须不同:

               参数个数不同,如method(int x)与method(int x,int y)不同

              参数类型不同,如method(int x)与method(double x)不同g

              参数顺序不同,如method(int x,double y)与method(double x,int y)不同

  •  重载只与方法名与参数类型相关与返回值无关

              如void method(int x)与int method(int y)不是方法重载,不能同时存在

  • 重载与具体的变量标识符无关

              如method(int x)与method(int y)不是方法重载,不能同时存在

区分方法

创建对象

对象是根据类创建的。在Java中,使用关键字new来创建一个新的对象。创建对象需要以下三步:

  • 声明:声明一个对象,包括对象名称和对象类型。
  • 实例化:使用关键字new来创建一个对象。
  • 初始化:使用new创建对象时,会调用构造方法初始化对象。

下面是一个创建对象的例子

public class People{
   public People(String name){
      //这个构造器仅有一个参数:name
      System.out.println("人的名字是 : " + name ); 
   }
   public static void main(String []args){
      // 下面的语句将创建一个People对象
      Puppy p= new People( "tom" );
   }
}

编译并运行上面的程序,会打印出下面的结果:

人的名字是 : tom

访问实例变量和方法

通过已创建的对象来访问成员变量和成员方法,如下所示:

/* 实例化对象 */
ObjectReference = new Constructor();
/* 访问类中的变量 */
ObjectReference.variableName;
/* 访问类中的方法 */
ObjectReference.methodName();

实例

下面的例子展示如何访问实例变量和调用成员方法:

public class People{
   int peopleAge ;
   public People(String name){
      // 这个构造器仅有一个参数:name
      System.out.println("人的名字是 : " + name ); 
   }
 
   public void setAge( int age ){
       peopleAge = age;
   }
 
   public int getAge( ){
       System.out.println("人的年龄为 : " + peopleAge ); 
       return peopleAge ;
   }
 
   public static void main(String []args){
      /* 创建对象 */
      People myPuppy = new People( "tom" );
      /* 通过方法来设定age */
      myPeople.setAge( 2 );
      /* 调用另一个方法获取age */
      myPeople.getAge( );
      /*你也可以像下面这样访问成员变量 */
      System.out.println("变量值 : " + myPeople.peopleAge ); 
   }
}

结果:

人的名字是 : tommy
人的年龄为 : 2
变量值 : 2

源文件声明规则

在本节的最后部分,我们将学习源文件的声明规则。当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。

  • 一个源文件中只能有一个public类
  • 一个源文件可以有多个非public类
  • 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
  • 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
  • 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  • import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。这些将在访问控制章节介绍。

除了上面提到的几种类型,Java还有一些特殊的类,如:内部类、匿名类。

Java包

包主要用来对类和接口进行分类。当开发Java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。

Import语句

在Java中,如果给出一个完整的限定名,包括包名、类名,那么Java编译器就可以很容易地定位到源代码或者类。Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类。

例如,下面的命令行将会命令编译器载入java_installation/java/io路径下的所有类

import java.io.*;

一个简单的例子

在该例子中,我们创建两个类:Employee 和 EmployeeTest

首先打开文本编辑器,把下面的代码粘贴进去。注意将文件保存为 Employee.java。

Employee类有四个成员变量:name、age、designation和salary。该类显式声明了一个构造方法,该方法只有一个参数。

Employee.java 文件代码:

import java.io.*;
 
public class Employee{
   String name;
   int age;
   String designation;
   double salary;
   // Employee 类的构造器
   public Employee(String name){
      this.name = name;
   }
   // 设置age的值
   public void empAge(int empAge){
      age =  empAge;
   }
   /* 设置designation的值*/
   public void empDesignation(String empDesig){
      designation = empDesig;
   }
   /* 设置salary的值*/
   public void empSalary(double empSalary){
      salary = empSalary;
   }
   /* 打印信息 */
   public void printEmployee(){
      System.out.println("名字:"+ name );
      System.out.println("年龄:" + age );
      System.out.println("职位:" + designation );
      System.out.println("薪水:" + salary);
   }
}

程序都是从main方法开始执行。为了能运行这个程序,必须包含main方法并且创建一个实例对象。

下面给出EmployeeTest类,该类实例化2个 Employee 类的实例,并调用方法设置变量的值。

将下面的代码保存在 EmployeeTest.java文件中。

EmployeeTest.java 文件代码:

import java.io.*;
public class EmployeeTest{
 
   public static void main(String []args){
      /* 使用构造器创建两个对象 */
      Employee empOne = new Employee("RUNOOB1");
      Employee empTwo = new Employee("RUNOOB2");
 
      // 调用这两个对象的成员方法
      empOne.empAge(26);
      empOne.empDesignation("初级程序员");
      empOne.empSalary(1000);
      empOne.printEmployee();
 
      empTwo.empAge(21);
      empTwo.empDesignation("小白程序员");
      empTwo.empSalary(500);
      empTwo.printEmployee();
   }
}

结果:

自己可以敲一下键盘就知道了………

对象在内存中的存在形式

Java vm内存:堆内存,栈内存

栈内存:随时开辟,使用,回收–>Java中的方法在运行起来的时候

会分配一个专有的占内存,方法运行结束,栈内存回收

堆内存:长久存在,用来存储对象的本体的一个空间–》一个公共的内存空间

Person p = new Person();

P:对象引用,引用变量,对象名-》存在方法栈内存中

new Persoon();对象本体–> 堆内存

对象本体的空间开辟,赋值等过程是相对比较消耗时间和空间的,没哟个对象本体,都是宝贵的资源,能够重用就重用,对象本体不应该被随便的回收,应该将对象本体放在一个稳定的空间内,所以将对象本体放在堆内存 中

凡是以对象本体和饮用方式存在的变量,都是引用数据类型的:数组,类的对象

*****基本数据类型的变量都存储在栈内存中,和对象本体不一样

栈:存储局部变量;堆:存储new出来的数组或对象

对象的回收

当一个对象本体失去所有的引用的时候,这个对象本体就变成一个弱引用对象

JVM中提供一种机制——垃圾回收机制,垃圾回收器Garbage Collector

垃圾回收机制会定期扫描内存空间,找到所有的弱引用对象,对其回收

类的构成

类的构成:变量和方法

1.变量:

    按照位置进行划分:

        全局变量:(属性)

            按照静态进行划分

                静态全局变量(类属性)

                非静态全局变量 (对象属性)

        局部变量:

            定义在方法中的局部变量

            定义在代码块中的局部变量

            定义在方法参数列表中的形参(形式参数)

 

局部变量

局部变量的生命周期:

想要访问一个局部变量,必须在这个局部变量的生命周期之内对其进行访问,在生命周期之外,要么这个变量尚未开始,要么这个变量的生命周期已经结束

形参(形式参数):

形参的生命周期贯穿整个方法

形参的传递机制:值传递:值的拷贝

对于基本数据类型:拷贝的是基本数据类型中的常量值,形参进行值得改变不会对实参的值发生影响

对于引用数据类型:拷贝的是引用变量中存储的对象本体的地址,实参将地址拷贝给形参,实参和形参实际上指向的对象本体其实是同一个,其中一个对这个地址所在的对象本体进行修改,大家都能看得见

全局变量:属性(Filed)

生命在类之中、方法之外的变量

全局变量的生命周期:在整个类中有效

属性:相关信息的描述,通过众多的属性的有机结合,就能够描述一个特定的群体

静态全局变量和非静态全局变量:

静态全局变量(类属性):

①类属性都是用static进行修饰

②作用:用来描述一个类的对象都具有而且值相同的属性

③类属性的值是全部对象共享的,如果有一个对象对类属性进行修改,其他对象的这个类型属性的值也会发生变化

④类属性尽量通过静态的方式进行访问——通过类名的方式进行访问:类属性既可以通过类名访问也可以通过对象名访问

⑤类属性的作用

  1。可以用来记录一个类的属性信息

  2.记录程序在运行过程当中产生的中间值

  3.在类与类之间传递信息

 

非静态全局变量(对象属性)

①对象属性都不用static修饰

②对象属性的作用;用来描述一个类的对象都具有,但是值个性化的属性

③对象属性的值是对象独享的,一个对象的对象属性发生改变,其他不会跟着发生改变 

④对象属性只能够通过非静态的方式进行访问:对象属性只能被对象名访问,类名不能够访问对象属性

 

其他:

类先定义在使用:用来new对象

Java中的命名法:驼峰命名

定义类、属性、方法:

①命名尽量使用英语单词

②明明使用的单词词组能够描述这个类、属性、方法的作用

③包名尽量完全使用小写字母:字母、数字、下划线  类名:如果一个类名由多个单词组成,各个单词的首字母大写,如果出现缩写,整个缩写单词都大写:TestMyMD5  变量名和方法名:第一个单词的首字母小写,之后其他单词的首字母大写

add()  addElement() eye eyeNumber  属性的命名不允许使用数字作为开头

 

空对象:null

①null并不依赖于任何一个类,null不是任何类的对象,没有任何一个类与null相对应

②但是任何一个类对象的引用变量都可以引用null String str = null;  Person p1 = null;  Car c1 = null;

③null或者指向null的引用变量不能够调用任何属性和方法,否则会引起NullPointerException

2.方法:

 

方法:

 

    按照功能进行区分:

 

        main方法:

        一般方法:

            按照静态与非静态:

                静态方法:

                非静态方法:    

        构造方法

定义:一系列相关处理过程的集合

方法的原子性:功能的模块化:在定义方法的时候,尽量将功能差分成不可再细分的子功能,大功能的完成取决于子功能呢的调用和配合

方法的内聚性和耦合性:高内聚,低耦合

内聚性:方法自行完成任务,尽量不依赖于外界条件的性质

耦合性:方法完成一项任务需要依赖多少的外界条件

方法:

    按照功能进行区分:

        main方法:

        一般方法:

            按照静态与非静态:

                静态方法:

                非静态方法:    

        构造方法:

 

main方法:

Main方法是所有程序的入口,程序运行起来首先执行main方法,在通过main方法中对其他方法的调用,达到运行程序的目的,

形参String[] args:外部程序命令集

在一般情况下,args != null,args.length == 0

一般方法

方法定义的一般语法

Pubilc static void main(String[] args){}

[访问权限修饰符][静态修饰符][final修饰符][同步修饰符]…返回值类型 方法名(形参列表)[声明异常抛出]

静态方法:类方法

①使用static关键字进行修饰

②静态方法的作用:静态方法一般都是充当工具方法的作用,使用者仅关心这个方法的执行过程和执行结果,没必要关心是谁提供的这个方法

④静态方法(类方法)调用属性:类方法只能够调用类属性,不能够调用对象属性

非静态方法:对象方法

①对象方法不使用static修饰

②对象方法仅能够通过对象调用:对象方法的调用结果取决于调用者

③对象方法的作用:因为调用者不同能够引起运行结果的不同,这样的方法应该声明成对象方法

④对象方法访问属性:对象方法即可以访问类属性也可以访问对象属性

 

 参数传递

参数传递,可以理解当我们要调用一个方法时,我们会把指定的数值,传递给方法中的参数,这样方法中的参数就拥有了这个指定的值,可以使用该值,在方法中运算了。这种传递方式,我们称为参数传递。

  • l  在这里,定义方法时,参数列表中的变量,我们称为形式参数
  • l  调用方法时,传入给方法的数值,我们称为实际参数

我们看下面的两段代码,来明确下参数传递的过程:

 

public class ArgumentsDemo01 {
    public static void main(String[] args) {
        int a=5;
        int b=10;
        change(a, b);//调用方法时,传入的数值称为实际参数
        System.out.println("a=" + a);
        System.out.println("b=" + b);
    }

    public static void change(int a, int b){//方法中指定的多个参数称为形式参数
        a=200;
        b=500;
    }
}

结果:

a=5
b=10

再看另一段代码

public class ArgumentsDemo02 {
    public static void main(String[] args) {
        int[] arr = { 1, 2, 3 };
        change(arr);// 调用方法时,传入的数值称为实际参数
        
    for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    public static void change(int[] arr) {// 方法中指定的多个参数称为形式参数
        for (int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }
    }
}    

程序的运行结果如下:

2
4
6

参数传递图解

通过上面的两段程序可以得出如下结论:

  •   当调用方法时,如果传入的数值为基本数据类型(包含String类型),形式参数的改变对实际参数不影响
  •   当调用方法时,如果传入的数值为引用数据类型(String类型除外),形式参数的改变对实际参数有影响

 参考资料:http://www.runoob.com/java/java-object-classes.html