Java类与对象 - Java基础知识 2

                                                                                     目录

基本概念

类与对象的定义与使用

对象实例化操作初步分析

引用传递分析

引用与垃圾产生分析

深入分析类与对象

成员属性封装

构造方法与匿名对象

this关键字

使用this调用当前属性

this调用本类方法

实战:简单Java类

static关键字

static定义属性

static定义方法

static应用案例

代码块

普通代码块

构造代码块

静态代码块


学习笔记

基本概念

面向过程对于一个问题的解决方案,一般不会做出重用的设计思想。

面向对象,主要的设计形式为模块化设计,并且 可以进行重用配置。在面向对象的设计中更多考虑的是标准。在使用的时候根据标准进行拼装。有三个特征:

  • 封装性:内部操作对外部不可见,当内部操作不可以直接使用的时候才是最安全的,如:有财不外露;
  • 继承性:在已有结构的基础上进行功能的扩充,如:手机;
  • 多态性:是在继承的基础上扩充的概念,指的是类型转换处理,如:人与狗不可入内;

面向对象在程序开发中的三个步骤:

  • OOA:面向对象分析;以生活中例子分析
  • OOD:面向对象设计;
  • OOP:面向对象编程。

面向对象核心组成:类与对象,如:汽车设计图纸与一个具体的车。

类是对某一类事物的共性的概念,而对象描述是一个具体的产物。类是一个模板,对象是可以使用的实例。先有类后有对象。在类中一般有两个组成:

  • 成员属性(Field):一些时候简称属性。如:一个人的姓名、年龄都是不同的,所以称之为属性。
  • 操作方法(Method):定义对象具体的处理行为。如:一个人可以唱歌、运动。

类与对象的定义与使用

在Java中类是一个独立的结构体,所以使用class进行定义,而在类中主要组成是成员属性与操作方法,成员属性是一个个变量,操作方法是一个个可以重复执行的代码。

范例:定义一个类

class Person{// 定义一个类
	// 成员属性
	String name ;
	int age ;
	// 操作方法
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

分析:    成员属性:name、age;     操作方法: tell(注意:通过类引用所以不加static)

类必须通过对象来使用,产生对象的语法如下:

  • 声明并实例化对象 :类名称 对象名称 = new 类名称(  ) ;
  • 分步骤完成:|- 声明对象:类名称 对象名称 = null ;  |- 实例化对象: 对象名称 = new 类名称();

当实例化对象过后,需要通过对象进行类中操作方法的调用,此时有两种调用方式:

  • 调用类中属性:实例化对象 . 成员属性;
  • 调用类中方法:实例化对象 . 方法名称();

范例:使用对象操作类

class Person{// 定义一个类
	// 成员属性
	String name ;
	int age ;
	// 操作方法
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{
	public static void main( String arges[] ){
		Person per = new Person() ; // 声明并实例化
		per.age  = 18 ; 
		per.name = "张三" ;
		per.tell() ; // 操作方法调用
	}
}

 如果没有进行对象成员属性的设置,声明实例化过后成员属性为默认值(数据类型的默认值 或 编写类时设置的);

对象实例化操作初步分析

Java中的类时属于引用数据类型,因此需要进行内存的管理,在进行操作的时候也会发生内存关系的变化。下面进行简单分析。

进行内存分析,需要给出常用的内存空间:

  • 堆内存:保存的是对象的具体信息,在程序中堆内存空间的开辟是通过new(开辟内存的最高级别);
  • 栈内存:一块堆内存的地址,即:通过地址找到堆内存,而后找到对象内容,为了分析简化理解为:对象名称保存在了栈内存之中。

产生对象的语法有两种:声明并实例化、分步骤完成

下面对上文代码进行分析:声明并实例化

分步骤完成:

public class JavaDemo{
	public static void main( String arges[] ){
		Person per = null ; // 声明对象 没有指向堆内存
		per = new Person() ;// 实例化对象
		per.age  = 18 ; 
		per.name = "张三" ;
		per.tell() ; // 操作方法调用
	}
}

注意:所有的对象在调用类中属性和方法时,必须实例化完成之后才能执行。

范例:错误的代码

public class JavaDemo{
	public static void main( String arges[] ){
		Person per = null ; // 申明对象
		per.age  = 18 ; 
		per.name = "张三" ;
		per.tell() ; // 操作方法调用
	}
}

代码之中只进行了声明,并没有进行实例化,所以无法调用。错误中NullPointerEcception(明确指出空指向异常),就是在堆内存没有开辟后产生的问题,并且只有引用数据类型才会出现这种错误。

引用传递分析

类本省属于引用数据类型,既然是引用数据类型,就牵扯到内存的引用传递,所谓的引用传递的本质是:同一块堆内存被不同的栈内存指向,也可以更换指向。

范例:定义一个引用传递分析的程序

public class JavaDemo{
	public static void main( String arges[] ){
		Person per1 = new Person() ; // 申明并实例化
		per1.age  = 18 ; 
		per1.name = "张三" ;
		Person per2 = per1 ; //引用传递
		per2.age = 80 ;
		per1.tell() ; // 操作方法调用 
        // 结果为80
	}
}

 

结果:80

这个时候的引用传递是在主方法中定义的,也可以通过方法实现引用传递处理。

范例:应用方法实现引用传递处理

public class JavaDemo{
	public static void main( String arges[] ){
		Person per = new Person() ; // 申明并实例化
		per.age  = 18 ; 
		per.name = "张三" ;
		change(per) ; // 引用传递 等价于 Person temp = per
		per.tell() ; // 操作方法调用
	}

	public static void change(Person temp){
		temp.age = 80 ;

	}
}

结果 : 80

与之前最大的区别在于,此实的程序将Person类的实例化对象(内存地址,数值)传递给change()方法之中,由于传递的是Person类型,所以change()接受的也是Person类型。

引用传递可以发生在方法上,一定要观察方法的参数类型,同时也要观察方法的执行过程。

引用与垃圾产生分析

因此所有的引用传递本质上是堆内存的调戏游戏。但是对于引用传递如果处理不当会造成垃圾的产生。将对垃圾的产生进行简单的分析。

范例:

public class JavaDemo{
	public static void main( String arges[] ){
		Person per1 = new Person() ; // 申明并实例化
		Person per2 = new Person() ; 
		per1.age  = 18 ; 
		per1.name = "张三" ;
		per2.age  = 19 ; 
		per2.name = "李四" ;

		per2 = per1 ; // 引用传递
		per2.age = 80 ;
		per1.tell() ; // 操作方法调用
	}


}

此时已经发生了引用传递,并且成功的完成了引用传递操作。下面进行内存分析:

所谓的垃圾空间指的是没有栈内存指向的堆内存空间,所有的垃圾空间将由GC(GarbageCollector(垃圾收集器))不定期进行回收,并且释放垃圾空间。但是如果垃圾过多一定会影响GC的回收性能,从而降低整体的程序性能。所以在程序开发中,垃圾的产生越少越好。

一个栈内存只包含一个堆内存的地址数据,如果发生更改,之前的地址数据将从此从栈内存中消失。

深入分析类与对象

成员属性封装

类是由属性与方法组成,一般而言方法都是对外服务的,所以不会进行封装处理,而对于属性由于其需要较高的安全型=性,所以往往需要进行其保护,这个时候就需要采用封装性对属性进行保护。

在默认情况下,在类中属性可以通过其它类通过对象调用。

范例:属性不封装情况下的问题

class Person{// 定义一个类
	// 成员属性
	String name ;
	int age ;
	// 操作方法
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person() ; // 申明并实例化
		per.name = "张三" ; // 在类外部修改属性
		per.age = 80 ; // 在类外部修改属性
		per.tell() ; // 操作方法调用
	}


}

此时在类Person中的属性name与age并没有进行封装处理,这样外部就可以直接调用的,但是有可能所设置的数据是错误的数据,如age = -18;

利用private关键字对属性进行封装处理。

范例:对属性进行封装

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 操作方法
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person() ; // 申明并实例化
		per.name = "张三" ; // 在类外部修改属性
		per.age = 80 ; // 在类外部修改属性
		per.tell() ; // 操作方法调用
	}


}

属性封装后对外部不可见,但对内部是可见的。要从外部访问属性,则在Java开发中提供如下要求:

  • 【setter、 getter】设置和取得属性可以使用setXxx()、getXxx()方法,以:private String name 为例:

          |- 设置属性,public void setName(name);

          |- 获取属性,public String getName()。

范例:实现封装

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 操作方法
	public void setName(String n){
		name = n ;	
	}
	public void setAge(int a){
		if (a>0){
			age = a ;
		}
	}
	public String getName(){
		return name ;
	}
	public int getAge(){
		return age ;
	}
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person() ; // 申明并实例化
		per.setName("张三") ;
		per.setAge(-18) ;

		per.tell() ; // 操作方法调用
	}


}

在以后写任何类得时候所有属性都必须用private封装(98%)。属性需要访问,必须提供setter、getter方法。

构造方法与匿名对象

现在的程序使用类是一般按照如下步骤进行:

  • 申明并实例化对象,这个时候实例化对象的属性,默认为数据类型的默认值
  • 需要通过一系列的setter方法进行设置属性内容。

范例:传统调用

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 操作方法
	public void setName(String n){
		name = n ;	
	}
	public void setAge(int a){
		if (a>0){
			age = a ;
		}
	}
	public String getName(){
		return name ;
	}
	public int getAge(){
		return age ;
	}
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 1. 对象的初始化准备
		Person per = new Person() ; // 申明并实例化
		per.setName("张三") ;
		per.setAge(-18) ;
		// 2. 对象的使用
		per.tell() ; // 操作方法调用
	}
}

如果类中属性太多,不适合用这种。Java提供构造方法实现实例化对象中的属性初始化处理。构造方法的定义要求如下:

  • 构造方法名称必须与类名称保持一致;
  • 构造方法不允许设置任何的返回值类型,即:没有返回值定义 (不加void);
  • 构造方法是使用new()时,方法自动调用的。

范例:定义构造方法

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法,无返回值定义
	public Person(String n , int a){
		name = n ; // 为类中属性赋值(初始化)
		age = a ; // 为类中属性赋值(初始化)
	}

	// 操作方法

	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 1. 对象的初始化准备
		Person per = new Person("张三", 18) ; // 申明并实例化
		// 2. 对象的使用
		per.tell() ; // 操作方法调用
	}
}

当前的实例化格式与之前的实例化格式进行一个比较:

  • 1)Person      2)per      =       3)new     4)Person();
  • 1)Person      2)per      =       3)new     4)Person("张三", 18);

             |- ”1)Person“ :主要是定义对象所属类型,类型决定你可以调用的方法;

             |-”2)per“ : 实例化对象的名称

             |-”3)new“:开辟一块堆内存空间

             |-”4)Person(”张三“, 18)“ :调用有参构造; ”4)Person()“:调用无参构造

在Java程序中考虑到程序的完整性,所有类都会提供构造方法。如果类没有定义构造方法,那么一定会提供一个默认的无参的构造方法,默认值为参数类型的默认值,它是在程序编译的时候自动创建的。如果明确有构造方法时,那么默认的构造方法不会被自动创建,也无法声明无参对象。

结论:一个类至少存在一个构造方法。

构造方法上不能设置返回值类型的原因?为什么不使用void定义?

分析:程序编译器根据代码结构进行编译处理的,执行也是根据代码结构执行的。如果在构造方法上使用void,就和普通方法结构完全相同的。普通方法与构造方法最大的区别:构造方法在类对象实例化的时候调用的,而普通方法是类对象实例化产生之后调用的。

构造方法是一种方法,方法都具有重载的特点,而构造方法在重载时只需要考虑参数的类型与个数即可。

范例:构造方法重载

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(){
		name = "无名氏" ;
		age = -1 ;
	}
	public Person(String n){
		name = n ;
	}
	public Person(String n , int a){
		name = n ; // 为类中属性赋值(初始化)
		age = a ; // 为类中属性赋值(初始化)
	}
	
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 1. 对象的初始化准备
		Person per = new Person("张三") ; // 申明并实例化
		// 2. 对象的使用
		per.tell() ; // 操作方法调用
	}
}

在进行多个构造方法定义时,按照参数个数升序排列。

经过分析,构造方法可以进行属性设置,setter也可以进行属性设置。构造方法是对象实例化的时候属性设置初始化内容,而setter拥有属性数据初始化的功能,还具有修改属性数据的功能。

范例:使用setter修改数据

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(){
		name = "无名氏" ;
		age = -1 ;
	}
	public Person(String n){
		name = n ;
	}
	public Person(String n , int a){
		name = n ; // 为类中属性赋值(初始化)
		age = a ; // 为类中属性赋值(初始化)
	}
	public void setAge(int a){
		age = a ;
	}
	
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 1. 对象的初始化准备
		Person per = new Person("张三") ; // 申明并实例化
		// 2. 对象的使用
		per.setAge(18);
		per.tell() ; // 操作方法调用
	}
}

经过分析过后发现,利用构造方法可以传递属性数据于是进一步分析对象的产生格式:

  • 定义对象名称: 类名称 对象名称 = null;
  • 实例化对象:对象名称 = new  类名称(),下划线上是真正对象的数据

如果这个时候,我们进行实例化对象来进行类的操作也是可以的,而这种形式的对象由于没有名字,称为匿名对象。

范例:观察匿名对象

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new Person("张三", 10).tell() ; 
	}
}

此时依然通过对象进行类tell()方法的调用,由于此时没有任何的引用名称,因此使用一次过后就将成为垃圾,所有的垃圾就将被GC进行回收与释放。

此时程序已经有了构造方法,那么通过一个程序进行构造方法的内粗你分析:

范例:编写一个分析程序

class Message{
	private String title ;
	public Message(String t){
		title = t ;
	}
	public void setTitle(String t){   //具有修改数据功能
		title = t ;		
	}
	public String getTitle(){
		return title ;
	}
}

class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(Message msg, int a){
		name = msg.getTitle() ; // 为类中属性赋值(初始化)
		age = a ; // 为类中属性赋值(初始化)
	}
	public Message getInfo(){
		return new Message(name + " : " + age) ;
	}
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Message msg =  new Message("mldn") ;
		Person per = new Person(msg, 20) ;
		msg = per.getInfo() ;
		System.out.println(msg.getTitle()) ;
	}
}

通过此程序,进行内存分析

只要是方法都可以传递任意的数据类型(基本数据类型、引用数据类型)

this关键字

this是Java中比较复杂的关键字,因为在使用形式上决定了它的灵活性,使用this可以实现三类结构的描述:

  • 当前类中的属性:this.属性;

  • 当前类中的方法:构造方法:this()、普通方法:this.方法名称();

  • 描述当前对象;

使用this调用当前属性

通过前面分析知道,利用构造方法或setter方法都可以进行类中属性的赋值,但是在进行赋值的时候,之前采用如下的形式:

范例:构造方法赋值


class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(String n, int a){
		name = n ; // 为类中属性赋值(初始化)
		age = a ; // 为类中属性赋值(初始化)
	}
	// setter getter 略
	public void tell(){
		System.out.println("姓名:" + name + "    " + "年龄:" + age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person("王五", 38  ) ;
		per.tell() ;
	}
}

可以看到构造方法中的参数n与a,是给name与age赋值,此时发现n与a 的参数名称不好。显然写成name与age更好,但这样无法进行属性的正确设置。

	public Person(String name, int age){
		name = name ; // 为类中属性赋值(初始化)
		age = age ; // 为类中属性赋值(初始化)
	}

在Java中“{}”是作为结构体的边界符,在程序里进行变量(参数、属性变量)使用时,都以大括号作为查找边界。当前name与age的查找边界是边界中,以就近原则,构造方法并没有访问类中属性,所以为了区分在类中属性与参数,往往在类中属性前加上this。


class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(String name, int age){
		this.name = name ; // 为类中属性赋值(初始化)
		this.age = age ; // 为类中属性赋值(初始化)
	}
	// setter getter 略
	public void tell(){
		System.out.println("姓名:" + this.name + "    " + "年龄:" + this.age ) ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person("王五", 38  ) ;
		per.tell() ;
	}
}

在以后开发中,访问本类中属性一定要加this。

this调用本类方法

this除了调用本类中属性,也可以调用本类方法,但调用本类方法必须考虑构造方法与普通方法。

  • 构造方法调用(this()): 使用关键字new实例化对象时候才会调用构造方法;
  • 普通方法的调用(this.普通方法名称()): 实例化对象产生过后就可以调用普通方法;

范例:调用类中普通方法


class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(String name, int age){
		this.name = name ; // 为类中属性赋值(初始化)
		this.age = age ; // 为类中属性赋值(初始化)
	}
	// setter getter 
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	//普通方法
	public void tell(){
		System.out.println("姓名:" + this.getName() + "    " + "年龄:" + this.getAge() ) ;
	}

}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person("王五", 38  ) ;
		per.tell() ;
	}
}

除了普通的方法调用,还需要构造方法的调用。对于构造方法的调用,必须放在构造方法中执行。现在假设类中一共有三种构造方法,不管调用那种构造方法,都执行一个输出语句“一个Person类的实例化对象”。

范例:传统做法实现


class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(){
		System.out.println("*** 一个新的操作对象实例化 ***") ;
	}
	public Person(String){
		this.name = name ;
		System.out.println("*** 一个新的操作对象实例化 ***") ;
	}
	public Person(String name, int age){
		this.name = name ; // 为类中属性赋值(初始化)
		this.age = age ; // 为类中属性赋值(初始化)
		System.out.println("*** 一个新的操作对象实例化 ***") ;
	}
	// setter getter 略

	//普通方法
	public void tell(){
		System.out.println("姓名:" + this.name + "    " + "年龄:" + this.age ) ;
	}

}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person("王五", 38  ) ;
		per.tell() ;
	}
}

如果“System.out.println("*** 一个新的操作对象实例化 ***") ”这句话是多行代码,则显然是代码重复问题。如果评价代码的好坏标准:

  • 代码结构可以重用,提供一个中间独立的支持
  • 没有重复代码

范例:利用this构造优化


class Person{// 定义一个类
	// 成员属性
	private String name ;
	private int age ;
	// 构造方法
	public Person(){
		System.out.println("*** 一个新的操作对象实例化 ***") ;
	}
	public Person(String name){
		this() ; // 调用无参构造
		this.name = name ;
	}
	public Person(String name, int age){
		this(name) ; // 调用单参数构造
		this.age = age ; 
	}
	// setter getter 略

	//普通方法
	public void tell(){
		System.out.println("姓名:" + this.name + "    " + "年龄:" + this.age ) ;
	}

}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person per = new Person("王五", 38  ) ;
		per.tell() ;
	}
}

这种才是设计结构合理的。

对于本类构造方法的调用必须注意以下几个问题:

  • 构造方法必须在实例化新对象时候调用,所以“this()”的语句必须放在构造方法的首行,包含普通方法不能调用构造方法;
  • 构造方法互相调用时,必须保留程序的出口,不能出现死循环。

死循环的提示:告诉用户,你出现了构造方法的递归调用。

范例:构造方法互相调用

现在定义一个描述员工信息的程序类,该类提供有:编号、姓名、部门、工资,在这个类之中提供四个构造方法:

【无参构造】编号1000,姓名定义为无名氏;

【单参构造】传递编号,姓名定义为“新员工”,部门定义为“未定”;

【三参构造】传递编号、姓名、部门,工资为2500。00;

【四参构造】所有信息都传递;

范例:代码的初期实现

class Emp{
	private long empno ;     //员工编号
	private String ename ;   //员工姓名
	private String dept ;    //员工部门
	private double salary ;  //员工工资
	
	public Emp(){
		this.empno = 1000 ;
		this.ename = "无名氏" ;
	}
	public Emp(long empno){
		this.empno = empno ;
		this.ename = "新员工" ;
		this.dept  = "未定" ;
  	}
	public Emp(long empno, String ename, String dept){
		this.empno  = empno  ;
		this.ename  = ename  ;
		this.dept   = dept   ;
		this.salary = 2500.00 ;
	}
	public Emp(long empno, String ename, String dept, double salary){
		this.empno  = empno  ;
		this.ename  = ename  ;
		this.dept   = dept   ;
		this.salary = salary ;
	}


	//setter getter略
	public String getInfo(){
		return "员工编号:" + this.empno +"\n"+
			   "   姓名:" + this.ename +"\n"+
			   "   部门:" + this.dept  +"\n"+
			   "   工资:" + this.salary ;
	}
	
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Emp emp = new Emp(7369, "SMTh", "财务部", 6500);
		System.out.println( emp.getInfo() ) ;

	}
}

此时发现代码有重复,此时可以用this优化:

class Emp{
	private long empno ;     //员工编号
	private String ename ;   //员工姓名
	private String dept ;    //员工部门
	private double salary ;  //员工工资
	
	public Emp(){
		this(1000, "无名氏", null, 0.0) ;
	}
	public Emp(long empno){
		this(empno, "新员工", "未定", 0.0) ;
  	}
	public Emp(long empno, String ename, String dept){
		this(empno, ename, dept, 2500.00) ;
	}
	public Emp(long empno, String ename, String dept, double salary){
		this.empno  = empno  ;
		this.ename  = ename  ;
		this.dept   = dept   ;
		this.salary = salary ;
	}


	//setter getter略
	public String getInfo(){
		return "员工编号:" + this.empno +"\n"+
			   "   姓名:" + this.ename +"\n"+
			   "   部门:" + this.dept  +"\n"+
			   "   工资:" + this.salary ;
	}
	
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Emp emp = new Emp(7369, "SMTh", "财务部", 6500);
		System.out.println( emp.getInfo() ) ;

	}
}

代码的任何位置上,都可能出现重复,消除重复的方法是先期学习的重点

实战:简单Java类

在以后的开发与设计中,简单Java类都将成为最重要的一个组成部分,慢慢的接触到正规的设计过后,简单Java类无处不在,并且有可能会产生一系列的变化。所谓简单Java类,可以是描述某类信息的程序类,例如:描述一个人、描述一本书、描述一个部门、描述一个雇员,并且在这个类中无复杂的逻辑操作,只作为信息存储的媒介。

对于简单的Java类而言,其核心开发结构如下:

  • 类名称一定要有意义,可以明确的描述某一事物;
  • 类之中的所有属性必须使用private进行封装,封装后的属性必须提供setter、getter;
  • 类之中可以有无数个构造方法,但必须保留有无参构造方法;
  • 类之中不允许出现任何的输出语句,所有的内容获取必须返回;
  • [非必须]类之中可以提供一个有获取详细信息的方法,定义为getInfo();
class Dept{ // 类名称可以明确描述出某类事物
	private long deptno ;
	private String dname ;
	private String loc ;
	public Dept(){} // 提供无参构造

	public Dept(long deptno, String dname, String loc){
		this.deptno = deptno ;
		this.dname  = dname  ;
		this.loc    = loc    ;

	}
	
	public String getInfo(){
		return "【部门信息】 部门编号:" + this.deptno +
				"、部门名称:" + this.dname +
				"、部门位置:" + this.loc ;
	}
	public void setDeptno(long deptno){
		this.deptno = deptno ;
	}
	public void setDname(String dname){
		this.dname = dname ;
	}
	public void setLoc(String loc){
		this.loc = loc ;
	}
	public long getDept(){
		return this.deptno ;
	}
	public String getDname(){
		return this.dname ;
	}
	public String getLoc(){
		return this.loc ;
	}
}

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Dept dept = new Dept(001, "平头哥", "天堂");
		System.out.println(dept.getInfo()) ;
	}
}

这中简单Java融合了到现在所学的内容,如数据划分、类的定义、private封装、构造方法、方法定义、对象实例化、this。

static关键字

static关键字,主要用来定义属性与方法。

static定义属性

在一个类中所有的属性被定义,内容都交由堆内存空间进行保存。

范例:观察传统情况

class Person{ // 创建所有同一个国家的类
	private String name ;
	private int age ;
	String country = "中华民国"; //国家,为了说明暂时不封装
	
	public Person(){}
	public Person(String name, int age){
		this.name = name ;
		this.age  = age  ;
	}
	// setter getter略
	public String getInfo(){
		return "姓名:" + this.name + 
				"、年龄:" + this.age + 
				"、国家"  + this.country ;
	}

}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person perA = new Person("张三", 10);
		Person perB = new Person("李四", 10);
		Person perC = new Person("王五", 11);
		System.out.println(perA.getInfo()) ;
		System.out.println(perB.getInfo()) ;
		System.out.println(perC.getInfo()) ;

	}
}

为了观察程序,进行内存分析

 

每一个对象保存各自的属性,国家解放了,变成“中华人民共和国”,如果有五千个对象。每一个对象都有自己的属性,就有重复保存数据和修改不方便的问题。传统开发中没有公共概念,最好的解决方案是将country修改为公共属性,就使用static关键字。形式如下:

范例:修改Person类定义使用static,定义公共属性

class Person{ // 创建所有同一个国家的类
	private String name ;
	private int age ;
	static String country = "中华民国"; //国家,为了说明暂时不封装
	
	public Person(){}
	public Person(String name, int age){
		this.name = name ;
		this.age  = age  ;
	}
	// setter getter略
	public String getInfo(){
		return "姓名:" + this.name + 
				"、年龄:" + this.age + 
				"、国家"  + this.country ;
	}

}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		Person perA = new Person("张三", 10);
		Person perB = new Person("李四", 10);
		Person perC = new Person("王五", 11);
		perA.country = "中华人民共和国" ;
		System.out.println(perA.getInfo()) ;
		System.out.println(perB.getInfo()) ;
		System.out.println(perC.getInfo()) ;

	}
}

此时会发现所有的country都发生了改变,所以这是一个公共属性,而此时的内存关系图如下:

但是对于static数据的访问,虽然可以通过对象访问,但需要通过所有对象的代表(类)访问,所以static属性可以通过类名称直接进行调用

Person.country = "中华人民共和国" ;

但同时static属性虽然定义在类中,但不受对象实例化的控制,即static属性可以在没有类对象实例化的时候使用。

范例:不产生实例化对象调用static属性


public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 没有实例化对象
		System.out.println(Person.country) ; 
		Person.country = "中华人民共和国" ;
		// 实例化对象
		Person per = new Person("张三", 10) ;
		System.out.println(per.getInfo()) ;
	}
}

以后再进行类设计的时候,首选非static属性(95%)。考虑到公共信息存储时才考虑static属性,非static属性必须在实例化对象之后才能使用,static在没有实例化直接通过类名称就可以调用。

static定义方法

static也可以进行方法的定义,static方法的特点在于,其可以直接使用类名称,在没有实例化对象的时候可以使用。

范例:定义static方法

class Person{ // 创建所有同一个国家的类
	private String name ;
	private int age ;
	private static String country = "中华民国"; //国家,为了说明暂时不封装
	
	public Person(){}
	public Person(String name, int age){
		this.name = name ;
		this.age  = age  ;
	}
	// setter getter略
	public static void setCountry(String c){ // static定义方法
		country = c ;
	}
	public String getInfo(){
		return "姓名:" + this.name + 
				"、年龄:" + this.age + 
				"、国家"  + this.country ;
	}

}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		// 没有实例化对象
		Person.setCountry("中华人民共和国") ;
		// 实例化对象
		Person per = new Person("张三", 10) ;
		System.out.println(per.getInfo()) ;
	}
}

这个时候对于程序而言,现在可以将方法两种:static方法、非static方法。这两种方法之间,在调用上就有了限制:

  • static方法只允许调用static属性或static方法;
  • 非static方法允许调用static属性或static方法。

static定义的属性与方法可以在没有进行实例化对象的情况下使用,而非static方法与属性只能在实例化对象对象的情况下才能使用。

如果可以理解这个限制,那么对于方法定义可以得到新的结论:在最早讲解方法定义的时候强调过:“当前定义的方法,都是在主类中定义的,并且由主类调用”。

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new JavaDemo().print() ; // 通过对象来调用static
	}
	public static void print(){
		System.out.println("这是一个测试") ;
	}

}

static定义的方法或者属性,都不是代码设计之初你需要考虑的内容,只有在回避实例化调用并且在描述公共属性的时候,才会考虑static定义的方法或属性。

static应用案例

为了加强理解,用两个程序来进行static应用提示。

范例:编写一个程序类,这个类可以实现实例化对象个数的统计,每一次创建一个新的实例化对象都可以实现一个统计操作。

分析:此时可以单独创建一个static属性,因为所有的对象都在共享同一个属性,那么构造方法中实现数据的统计处理:

class Book{
	private String title ;
	private static int count = 0 ;
	public Book(String title){
		this.title = title;
		count ++ ;
		System.out.println("第" + count + "新的图书创建出来") ;
	}
}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new Book("Java") ; new Book("JSP") ; new Book("SPRING") ;
		

	}

}

范例:实现属性的自动命名处理,没有传递title,使用“NONETITLE-编号”定义

class Book{
	private String title ;
	private static int count = 0 ;
	public Book(){
		this("NOTITLE - " + count++) ;
	}
	public Book(String title){
		this.title = title;
		count ++ ;
	}
	// setter getter 略
	public String getTitle(){
		return this.title ;
	}
}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		System.out.println(new Book("Java").getTitle()) ;
		System.out.println(new Book("JSP").getTitle()) ;
		System.out.println(new Book("Spring").getTitle()) ;
		System.out.println(new Book().getTitle()) ;//无参
		System.out.println(new Book().getTitle()) ;//无参
	}

}

这样处理的好处是,避免了在没有设置title属性时内容为null的重复问题。

代码块

在程序之中,使用大括号定义的结构,称之为代码块,而根据代码块出现位置以及定义的关键字的不同,代码块可以分为:普通代码块、构造块、静态块、同步代码块,其中对于同步代码块对于多线程讲解。

普通代码块

普通代码块的特点是定义在一个方法之中代码块。

范例:观察一个程序

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		if (true){
			int x = 10 ; // 局部变量
			System.out.println("x = " + x) ;
		}
		int x = 100 ;// 全局变量 相对而言
		System.out.println("x = " + x) ;
	}
}

按照Java标准规定,相同名称的变量不能在同一个方法之中存在的,由于此时由不同的分界描述。要定义普通代码块,直接将if 语句取消即可。

public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		{//普通代码块
			int x = 10 ; // 局部变量
			System.out.println("x = " + x) ;
		}
		int x = 100 ;// 全局变量 相对而言
		System.out.println("x = " + x) ;
	}
}

普通代码块的最大特征,可以在一个方法之中可以进行一些结构的拆分,以防止相同变量名称所带来的互相影响。

构造代码块

 构造块是定义在一个类中。

范例:观察构造块

class Person{
	public Person(){
		System.out.println("【构造方法】Person类构造方法执行");
	}
	{
		System.out.println("【构造块】Person构造块执行");
	}
}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new Person() ;
		new Person() ;
		new Person() ;
	}
}

可以看出构造块先于构造方法执行,并且每一次实例化新对象的时候都会调用构造块中的代码。

静态代码块

静态代码块主要是指使用static关键字定义的代码块,静态块的定义需要考虑两种情况:一种是主类中定义静态块、非主类中定义静态块。

范例:在非主类中进行静态块的定义

class Person{
	public Person(){
		System.out.println("【构造方法】Person类构造方法执行");
	}
	static{//一般用来static属性初始化的
		System.out.println("【静态块】静态块执行") ;
	}
	{
		System.out.println("【构造块】Person构造块执行");
	}
}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new Person() ;
		new Person() ;
		new Person() ;
	}
}

此时发现静态块优先于构造块执行,并且无论多少个对象出现,静态代码块只会执行一次。静态代码块主要是为了类中static属性初始化。

范例:观察静态属性的初始化

class Message{
	public static String getCountry(){
		//该信息内容可能来自于网络或其它服务器
		return "中华人民共和国" ;
	}
}

class Person{
	private static String country ;
	static{// 可能有多个语句执行
		country = new Message().getCountry() ; // 编写一部分代码
		System.out.println(country) ;

	}

}
public class JavaDemo{ // 主类
	public static void main( String arges[] ){
		new Person() ;
	}
}

对于静态代码块还需要考虑在主类中定义的形式。

范例:在主类中进行静态代码块的定义

public class JavaDemo{ // 主类
	static{
		System.out.println("****** 程序初始化 *****") ;
	}
	public static void main( String arges[] ){
		System.out.println("这是一个测试程序");
	}
}

静态代码块优先于主方法先执行。

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值