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