java从零开始系列——(二)面向对象 下

luoyjx · 2014-09-08 23:01 · 1062次阅读

目录

    1.基本数据类型的包装类 
    2.String类的基本使用 
    3.处理对象  
    4.final、static修饰符、单态设计模式 
    5.代码块种类  
    6.抽象类 
    7.接口
    8.多态 
    9.设计模式 
    10.内部类 
    11.枚举类 
    12.对象与垃圾回收

1.基本数据类型的包装类

    在Java 的设计中提倡一种思想:“一切皆对象”,那么这样一来就出现了一个矛盾。从数据类型的划分中可以知道 Java 中的数据类型分为基本数据类型和引用数据类型。基本数据类型怎么能够成为对象呢?此时,就需要将基本数据类型进行包装。将八种基本类型变为一个类的形式,这就是包装类的作用。这样就可以以对象的形式操作基本数据类型。

基本数据类型对应的包装类

装箱及拆箱的概念: 
将基本数据类型变为包装类称为装箱; 
将包装类的数据类型变为基本数据类型称为拆箱。
以 Integer为例: 
public class AA{ 
  public static void main(String args[]){ 
    int x = 30 ;    //  基本数据类型 
    Integer i = new Integer(x) ;  //  装箱:将基本数据类型变为包装类 
    int temp = i.intValue()  ;//  拆箱:将一个包装类变为基本数据类型 
  } 
}

在JDK1.5 之前对于程序本身来说包装类是不能直接进行“+、-、*、/、++、–”操作的。
因为包装类是一个类。但是在 JDK1.5 版本之后,对程序的包装类功能进行了改变,增加了自动装箱及自动拆箱的功能,而且也可以使用包装类直接进行数字运算。
public class AA{ 
  public static void main(String args[]){ 
    Integer i = 30 ; //  自动装箱成 Integer 
    Float f = 30.3f ;  //  自动装箱成Float 
    int x = i ;      //  自动拆箱为int 
    float y = f ;    //  自动拆箱为float 
  } 
};  

在包装类中,实际上还存在一个最大的特点,就是可以将字符串变为指定的数据类型。 
包装类在实际中用得最多的还是在于字符串变为基本数据类型的操作上。例如:将一个全由数字组成的字符串变为一个 int 类型的数据。在 Integer类中分别提供了以下的方法: 
Integer 类(字符串转 int型) 
  public static int parseInt(String s) throws NumberFormatException

String类 

String类的实例化方式有两种:
直接赋值,字符串常量存放在静态数据区。
通过关键字new,使用new关键字进行String 变量赋值,将会开辟两个空间。赋值成功后,有一个空间中的数据将会变成垃圾。

String类两种方式创建的内容比较,== 和 equals 的区别
== 比较的是内存地址
equals 比较的是地址上存的值

public class Test {

	public static void main(String[] args) {
		String s1 = "test";
		String s2 = "test";
		String s3=new String("test");
		String s4=new String("test");
		System.out.println(s1 == s2);
		System.out.println(s1.equals(s2));
		System.out.println(s3 == s4);
		System.out.println(s3.equals(s4));
		s1 += "shenZhen";
       	s2 += "shenZhen";
       	System.out.println(s1 == s2);
		System.out.println(s1.equals(s2));
	}

}

String 字符串池

Java程序可包含众多字符串值。
“字符串池”中存放所有在程序中创建的字符串值。
任何时候创建字符串值,系统都会搜索字符串池,查看是否存在该字符串值,如果存在,则不在字符串池中为该字符串创建新的实例,而是将一个现有实例赋值给新字符串。这会节省内存。

String 类的方法使用 

请查看API文档,下面是常用的方法:

public String(char[] value)   //直接将一个字符数组变为一个字符串 
public String(char[] value,int offset,int count)   //将一个指定范围的字符数组变为字符串 
public String(byte[] bytes)   //将一个byte数组变为字符串 
public String(byte[] bytes,int offset,int length)   //将一个指定范围的byte 数组变为字符串 
public char[] toCharArray()   //把一个字符串变为字符数组 
public char charAt(int index)   //从字符串中取出指定位置的字符 
public byte[] getBytes()   //将一个字符串变为byte 数组 
public int length()   //取得字符串长度 
public int indexOf(String str)   //从开头查找指定字符串的位置 
public int indexOf(String str,int fromIndex)   //从指定位置查找指定字符串的位置 
public String trim()   //清除字符串左右两端的空格 
public String substring(int beginIndex)   //从指定位置开始,一直取到尾进行字符串的截取 
public String substring(int beginIndex,int end)    //指定截取字符串的开始点和结束点 
public String[] split(String regex)    //按照指定的字符串对字符串进行拆分(*) 
public String toUpperCase()    //将一个字符串全部变为大写字母 
public String toLowerCase()    //将一个字符串全部变为小写字母 
public boolean startsWith(String prefix)    //判断是否以指定的字符串开头 
public boolean endsWith(String suffix)      //判断是否以指定的字符串结尾 
public boolean equals(String str)     //判断两个字符串内容是否相等 
public boolean equalsIgnoreCase(String str)    //不区分大小写比较两个字符串是否相等 
public String replaceAll(String regex,String replacement)  //字符串替换(*) 
public static String valueOf(XXX X) //XXX为基本数据类型 

处理对象

Java对象都是Object类的实例,都可以直接调用该类中定义的方法,这些方法提供了处理Java对象的通用方法。
如下代码
Person p=new Person()
System.out.println§;
System.out.println(p+””);
System.out.println(p.toString());

所有Java对象都可以转换为字符串

对象比较

Java程序中测试两个变量是否相等有两种方式,一种是利用==运算符,另一种是利用equals方法。
当使用==来判断两个变量是否相等时,如果两个变量是基本数据类型的变量,且都是数值类型,只要两个变量的值相等,就会返回布尔值true。但对于两个引用类型的变量,必须他们指向同一个对象时,才会返回布尔值true。
equals方法是Object类提供的一个实例方法,所有引用变量都可以调用该方法判断是否与其他变量相等。当两个引用变量指向一个对象才会返回true,Object类提供的equals方法没有太大意义,如果希望采用自定义的相等标准,可以采用重写equals方法来实现。

instanceof用法

用来判断某个对象是否是某个类的实例对象,返回值为布尔值。
Instanceof使用语法:
对象  instanceof  类    返回 boolean 类型 
例如:

if("fd" instanceof String){
	System.out.println("yes");
}else{
	System.out.println("no");
}

final、static修饰符 final类

Java编程语言允许关键字final修饰类。如果这样做了,类便不能被继承。 
final方法
方法也可以被标记为final。被标记为final的方法不能被覆盖。
final变量
如果变量被标记为final,其结果是使它成为常数。

(常被问到) 
Final修饰类
final修饰的类不可有子类。如java.lang.String、java.lang.Math都是一个final类,它们不可以有子类。当子类继承父类是,将可以访问到父类内部数据,并可通过重写父类方法来改变父类方法的实现细节,这可能导致一些不安全的因素,可以使用final修饰类。

final修饰方法
final修饰方法不可被重写,java提供的Object类中有一个final方法:getClass();,java不希望任何类重写这个方法。
final修饰的方法不能重写,但可以重载。
Final修饰变量,称为常量
常量必须全部大写。
Final修饰成员变量和修饰局部变量的区别:
使用final修饰成员变量时,要么在定义程序变量的时候指定初始化值,要么在初始化块,构造方法为成员变量赋值。如果定义该成员变量时候指定了默认值,那么不能在初始化块、构造方法重新赋值。Final成员变量必须由程序员显示初始化,系统化不会对final成员变量进行隐式初始化。
Final修饰局部变量,必须由程序员显示初始化,可以先定义,后赋值,但只能一次,不能重复赋值。
Final修饰基本类型和引用类型变量的区别
Final修饰基本类型变量时,不能对基本类型变量重新赋值。
Final修饰引用类型的变量,只要保证这个变量所引用的地址不改变,但这个变量指向的对象可以发生改变。

一般而言,我们设计一个class时,其实就是在描述其对象的外观长相及行为举措。除非以new来产生对象,否则并不存在任何实质的对象。产生对象之际,存储空间才会分配出来,其方法才可供外界使用。
但是有两种情况,是上述方式无法解决的。
我们希望不论产生了多少个对象,或不存在任何对象的情况下,那些特定数据的存储空间都只有一份。
我们希望某个函数不要和class object绑定在一起。
通过关键字static ,我们就可以处理这两种情况。
static关键字用来声明成员属于类,而不是属于类的对象。 (意思是,static的成员被所有类对象共享)

static 修饰成员变量

类变量可以被类的所有对象共享,无论产生多少对象,存储空间只有一份。因为static 的数据,是运行在内存的数据区。
public class Test { static int i = 10; public static void main(String[] args) { Test t = new Test(); Test t1 = new Test();

		System.out.println("t.i = " + t.i);
		System.out.println("t1.i = " + t1.i);

		t.i++;

		System.out.println("t.i = " + t.i);
		System.out.println("t1.i = " + t1.i);
	}
}

static修饰方法

静态方法可以通过类名直接调用该方法,而不用通过对象调用。使用 static 方法,不能直接调用非 static的属性或方法。
静态方法不能被覆盖成非静态。同样,非静态方法也不能被覆盖成静态方法。
public class Test { static int i = 10; static void change() { i++; } public static void main(String[] args) { Test t = new Test(); t.change();

		Test.change();

		System.out.println(Test.i);
	}
}

nstatic代码

l当类被装载时,静态块代码只执行一次。类中不同的静态块按它们在类中出现的顺序被执行。

全局常量static final 

使用 static final 关键字联合声明的变量称为全局常量: 
public static final String INFO = “abc”;

单态设计模式

单态设计模式即是类在内存中只能创建一个实例对象,也就是采取一定的方法保证在整个的软件系统中,对某个类只能产生一个对象实例,并且该类只提供一个取得其实例对象的方法。
如果我们要让类在一个虚拟机中只能产生一个对象.我们首先必须将类的构造方法的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,但在类内部仍可以产生该类的对象.因为在类的外部开始还无法得到类的对象,只能调用该类的某个静态方法一返回类内部创建的对象,静态方法只能访问类中的静态成员变量,所以指向类内部产生的该类对象的变量也必须定义成静态的. 

就一句话,不管多少引用,真正对象只有一个。

代码示例:

class Singleton {
	private Singleton() {
	}

	private static Singleton singleton = null;

	public static synchronized Singleton getSingleton() {
		if (singleton == null) {
			singleton = new Singleton();
		}

		return singleton;
	}
}

单例模式的要点有三个:
一是某个类只能有一个实例;
二是它必须自行创建这个实例;
三是它必须自行向整个系统提供这个实例。

单态设计模式实际应用:
1.在多个线程之间,比如servlet环境,共享同一个资源或者操作同一个对象
2.在整个程序空间使用全局变量,共享资源
3.在规模系统中,为了性能的考虑,需要节省对象的创建时间等

代码块种类 java中存在四种代码块: 

1、普通代码块:是直接写在各个方法中的代码块 
2、构造块:是直接写在类中的代码块,在实例化对象的时候调用,而且每实例化一个对象就要调用一次构造块(多次调用)。构造块优先于构造方法执行。 
3、静态块:是使用static声明的代码块,静态块只调用一次,而且优先于构造块执行。 作用:为static类型的属性初始化 
4、同步代码块:主要出现在多线程中 

类的初始化顺序 

静态代码块的执行顺序及执行次数: 

  1. 主方法中的静态块优先于主方法执行; 

  2. 主方法优先于其他类中的静态块执行; 

  3. 在普通类中定义的静态块,优先于构造块执行; 

  4. 父类的静态代码块优先于子类的静态代码块执行; 

  5. 子类的静态代码块优先于父类的构造块执行; 

  6. 不管有多少个实例化对象产生,静态代码块只执行一次 

  7. 父类的构造块和构造代码块,优先于子类的构造块; 

  8. 构造块优先于构造代码块执行。 

  9. 构造块和构造代码块执行的次数与声明的对象数相等,父类同样。   

    class SuperClass{ static{ System.out.println(“1、父类static代码块”); } { System.out.println(“2、父类构造块”); } public SuperClass(){ System.out.println(“3、父类构造代码块”); } }

    class SunClass extends SuperClas{ static{ System.out.println(“4、子类static代码块”); } { System.out.println(“5、子类构造块”); } public SunClass(){ System.out.println(“6、子类构造代码块”); } }

    public class StaticDemo { static{ System.out.println(“7、主类static代码块”); } { System.out.println(“8、主类代码块”); } public static void main(String[] args) { // TODO Auto-generated method stub System.out.println(“9、主方法开始执行”); SunClass sc1=new SunClass(); SunClass sc2=new SunClass(); SunClass sc3=new SunClass(); System.out.println(“10、主方法执行结束”); } }

抽象类 Animal 类,动物的叫声方法enjoy(),父类定义和实现其叫声,没有什么意义,因为每个子类,具体的某种动物,它的叫声是不一样的。因此,在父类Animal中,只需要声明一下,有叫声这个方法,具体的实现,就交由子类来进行。

抽象类的概念:包含一个抽象方法的类就称为抽象类。 
抽象方法:只声明而未实现(为实现,就是说方法声明后面没有“{}”)的方法称为抽象方法。抽象方法必须使用 abstract 关键字声明。 

抽象类的定义及使用规则

抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类可以没有抽象方法。
抽象方法和抽象类的规则
抽象类必须使用abstract修饰,抽象方法也必须使用abstract修饰符来修饰,抽象方法不能有方法体。抽象类必须被子类继承,子类(如果不是抽象类)必须覆写抽象类中的全部抽象方法
抽象类不能实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。即使抽象类里不包含抽象方法,这个抽象类也不能创建实例,可以通过非抽象子类来创建抽象类的对象。
抽象类可以包含属性、方法(普通方法、抽象方法)、构造器、初始块、内部类、枚举六种成分。抽象类的构造器不能用于创建实例,主要是用于被子类调用。
含有抽象方法的类(包括直接定义了一个抽象方法;继承了一个抽象父类,但没有完全实现父类包含的抽象方法;以及实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。

abstract class A{  //  是定义了一个抽象类 
  public static final String FLAG = "CHINA" ;  //  全局常量 
  private String name = "ITjob" ;  //  定义一个普通的属性 
  public void setName(String name){ 
    this.name = name ; 
  } 
  public String getName(){ 
    return this.name ; 
  } 
  public abstract void print() ;    //  定义抽象方法 
}

抽象类的问题: 
问题1:一个抽象类可以使用 final 声明吗? 
问题2:一个抽象类可以使用 static关键字修饰抽象方法吗?
问题3:一个抽象类中可以定义构造方法吗?
问题4:一个抽象类是否跟普通类一样是单继承?答案

答案放在最后吧。

抽象类的继承

抽象类,可以继承于抽象类
抽象类,可以继承于普通类
抽象类,可以实现接口
抽象类实现的接口中定义的函数,抽象类中可实现覆盖,继承抽象类的子类,也可以实现覆盖

抽象类作用

抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。以这个抽象类作为其子类的模板,从而避免了子类设计的随意性。
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会大致保留抽象类的行为方式。

接口 从本质上讲,接口是一种特殊的抽象类,interface:totally abstract class(完全抽象类)

这种抽象类中只包含全局常量和公共的抽象方法的定义,而没有变量和方法的实现。可以说接口是抽象方法和常量值定义的集合。
如果一个类中完全是由全局变量(static final 声明)和抽象方法(abstract 声明)组成,就可以将其定义成一个接口。 
接口是用关键字interface来定义的,接口是客户端代码与提供服务的类之间的“规约”。接口定义举例说明:

public interface Fly {
	double velocity = 635.66d;
	void flyHighness();
}

接口定义

接口的定义格式:

interface  接口名称{ 
  全局常量(static final); 
  抽象方法(abstract); 
} 

在interface 中所有的属性都是public static final的,即使我们没有显式声明。
在interface中所有的方法都是public abstract的,即使我们没有显式声明。

接口的继承

一个接口虽然不能继承类,但是在 Java 中一个接口可以通过 extends 关键字同时继承多个接口,实现接口的多继承。格式如下:
interface 子接口 extends 父接口 A,父接口 B,…{ }

接口的使用,弥补了Java技术单继承规则的不足。

接口的实现与抽象方法相似,当类实现某个接口时,它必须实现这个接口的所有方法。
例如,定义一个Flyer接口,它支持三种操作:takeoff( ) 、land( )、fly( )。类Airplane可以实现Flyer。

一:接口:Flyer	
		public interface Flyer {
			public void takeoff( );
			public void land( );
			public void fly( );
		}
二:类Airplane实现接口Flyer
		public class Airplane implements Flyer{
			public void takeoff( ){
				//code….
			}
			public void land( ){
				//code….
			}
			public void fly( ){
				//code…
			}
		}

Java允许多个类(抽象类、非抽象类)实现同一个接口
Java同一个类(抽象类、非抽象类)可以实现多个接口
接口不能继承抽象类,但是在 Java 中一个接口可以通过 extends 关键字同时继承多个接口,实现接口的多继承。
继承和接口的混合使用
与继承关系类似,接口与实现类之间存在多态性

同一个类实现多个接口,声明的接口之间由逗号隔开

继承类或继承抽象类与实现接口可以混合使用

面向接口编程

接口体现的是一种规范和实现分离的设计哲学,充分利用接口可以极好地降低程序各模块之间的耦合,从而提高系统的可扩展性和可维护性。
基于这中原则,很多软件架构设计理论都倡导“面向接口”编程,而不是面向实现类编程。希望通过面向接口编程来降低程序的耦合。
后面介绍简单工厂模式来说明面向接口编程的优势。

抽象类和接口选择概括

什么时候使用接口

对于下述情况,应该使用接口:
声明方法,期望一个或更多的类来实现该方法。
揭示一个对象的编程接口,而不揭示类的实际程序体。(当将类的一个包输送到其它开发程序中时它是非常有用的。)
捕获无关类之间的相似性,而不强迫类关系。

什么时候使用抽象类

如果接口不能预测以后版本中需要添加的新成
员,那么就使用抽象类。

多态 

多态性在面向对象中是一个最重要的概念,在 Java 中面向对象主要有以下两种体现: 
方法的重载与覆写 
对象的多态性 

多态-方法的重载与覆写

多态,也叫动态绑定或迟绑定。
动态绑定是指“在执行期间(而非编译期间)”判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
执行期间:运行 java …
编译期间:运行 javac …

class Animal {
	private String name;

	Animal(String name) {
		this.name = name;
	}

	public void enjoy() {
		System.out.println("叫声...");	
	}
}

class Cat extends Animal {
	// 毛发颜色
	private String hairColor;

	Cat(String n, String c) {
		super(n);
		hairColor = c;
	}

	public void enjoy() {
		System.out.println("猫叫声...");	
	}
}

class Dog extends Animal {
	// 种类
	private String breed;

	Dog(String n, String b) {
		super(n);
		breed = b;
	}

	public void enjoy() {
		System.out.println("狗叫声...");
	}
}
class Lady {
	private String name;
	private Animal pet;

	Lady(String name, Animal pet) {
		this.name = name;
		this.pet = pet;
	}

	public void myPetEnjoy() {
		pet.enjoy();
	}
}

public class Dynamic {
	public static void main(String[] args) {
		Cat c = new Cat("Tom", "blue");
		Dog d = new Dog("Pert", "shepherd dog");

		Lady l1 = new Lady("l1", c);
		Lady l2 = new Lady("l2", d);

		l1.myPetEnjoy();
		l2.myPetEnjoy();
	}
}

多态-对象的多态性

对象的多态性可以直接应用在抽象类和接口上。 
对象的多态性主要分为以下两种类型: 
 向上转型:子类对象父类对象 
对于向上转型,程序会自动完成。 
格式:父类  父类对象  =  子类实例; 
 向下转型:父类对象子类对象
对于想向下转型时,必须明确的指明要转型的子类类型。 
格式:子类  子类对象  = (子类)父类实例; 

在父类对象向子类对象的转换的过程中,需要注意的是: 如果父类对象是实例化的父类对象而不是用子类对象转换过来的对象,则不能在强制转换为子类对象,否则会出现ClassCastException类转换异常. 也就是说,能进行父类对象向子类对象转换的前提是: 之前是使用子类对象的实例来初始化得父类对象. 
为了使强制转换成功,必须确认对象是属于子类的实例,如果超类对象不是子类的实例,则会发生运行时异常。这就用到了instanceof 操作符。
 对象在进行向下转型之前一定要先发生向上转型,要使用 instanceof关键字判断 
例一: class Athlete { }

class Gymnast extends Athlete {
	void dis() {
		System.out.println("调用方法 dis()");
	}
}

class FootballAthlete extends Athlete {
	void show() {
		System.out.println("调用方法 show()");
	}
}

class Employ {
	Employ(Athlete alt) {
		// 判断是否属于这个对象
		if (alt instanceof Gymnast) {
			// 对象类型的强制转换
			((Gymnast) alt).dis();
		} else if (alt instanceof FootballAthlete) {
			((FootballAthlete) alt).show();
		}
	}
}

public class Test {
	public static void main(String[] args) {
		new Employ(new Gymnast());
	}
}

抽象类与接口的应用 
为抽象类和接口实例化 
在Java 中可以通过对象的多态性,为抽象类和接口实例化,这样再使用抽象类和接口的时候就可以调用本子类中所覆写过的方法了。 之所以抽象类和接口不能直接实例化,是因为其内部包含了各个抽象方法,抽象方法本身都是未实现的方法,所以无法调用。 
通过对象多态性可以发现,子类发生了向上转型关系之后,所调用的全部方法都是被覆写过的方法。 
抽象类的应用——定义模板
假设一种场景:“假设人分为学生和工人,学生和工人都可以说话,但是学生和工人说话的内容是不一样的,也就是说,说话的这个功能应该是一个具体功能,而说话的内容就要由学生或工人来决定了”,所以此时就可以使用抽象类实现这种场景。 
接口的应用——制定标准 
接口在实际中更多的作用是用来制定标准的。比如说:“U盘和打印机都可以插在电脑上使用,这是因为他们都实现了 USB的接口,对于电脑来说,只要是符合了 USB接口标准的设备就都可以插进来。 

工厂设计模式 
工厂设计模式是在Java 开发中最常使用的一种设计模式。 

代理设计模式 
代理设计是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主体负责其他相关业务的处理,就好比在生活中经常使用到的代理上网那样,客户通过网络代理链接网络,由代理服务器完成用户权限,访问限制等与上网操作相关的操作。也是在 Java 开发中使用较多的一种设计模式 

适配器设计
适配器设计主要用于 Java 图形界面。 
在Java 程序中,如果一个类要实现一个接口,则肯定要覆写此接口中的全部抽象方法。 此时一个接口中定义的抽象方法过多,但是在子类中又用不到这么多抽象方法的话,在子类中又必须覆写此接口中的全部抽象方法,肯定会浪费大量的人力去编写不必要的代码。 
此种情况下,就需要一个中间的过渡,但是此过渡类又不希望直接使用,因此将次过渡类定义成抽象类最合适,即:一个接口首先被一个抽象类(次抽象类通常称为适配器类),并在此抽象类中实现若干方法(方法体为空),则以后的子类直接继承此抽象类,就可以有选择的覆写所需要的方法。 

内部类的扩展 
开发中,一个抽象类中也可以包含一个内部类。反之,在一个接口中也可以包含一个抽象类。但是,从实际开发中,此种设计并不常见。因为这样做代码的结构有些混乱。   

抽象类与接口之间的关系 

在开发中,一个类永远不要去继承一个已经实现好的类。要么继承抽象类,要么实现接口。如果接口和抽象类同时都可以使用的话,那么优先使用接口,避免单继承局限。 

内部类  内部类,也叫做嵌套类。内部类允许一个类定义被放到另一个类定义里。

内部类的出现,初始思想是JDK1.2版本为解决一个类能访问另外一个类的私有成员。
内部类分为:非静态内部类、静态内部类
内部类,可以直接访问外部类的属性和方法,包括private 的。
外部类,不能直接访问内部类的成员,哪怕是public 的.
外部类,访问内部类的成员,包括private 的,是通过内部类的对象来进行访问的(通过new实例内部类来访问)。
我们可以把内部类看作“方法”一样,在使用的时候调用执行。
我们也可以把内部类看作“属性”一样,在构造内部类对象的时候,也会在堆里为内部类的属性分配存储空间。
内部类使用static 关键字声明,此类内部类就称为静态内部类(外部类)。可以直接通过“外部类.内部类”的形式进行访问。
static类型的内部类不能访问非静态的外部类成员。
非静态内部类不能定义静态成员。
外部类属性、内部类属性与内部类里的方法的局部变量同名,则可以通过使用this(内部类属性)、外部类名.this(外部类属性)

静态内部类

内部类的对象总是创建在外部类中。但我们可以从其它类创建内部类对象。静态内部类,必须首先创建外部类对象,然后使用下面语法来创建内部类对象:
格式:
外部类.内部类  内部类对象  =  外部类实例.new  内部类(): 

内部类使用static 关键字声明,此类内部类就称为静态内部类
静态内部类,使用下列语法创建内部类对象:
外部类.内部类  内部类对象  = new 外部类实例. 内部类():

以上面的方式来创建内部类对象,阅读费解,且相应违反Java的原则。
一般来说,构造内部类对象,调用外部类一方法,返回内部类对象:
Inner getInnerBuild() { return new Inner(); }

例一:
public class Outer {
	private int k = 10;
	class Inner {
		Inner() {
			System.out.println("k = " + k);
		}

		void dis() {
			System.out.println("itJob");
		}
	};

	// 返回内部类对象
	Inner getInnerBuild() {
		return new Inner();
	}

	public static void main(String[] args) {
		Outer otr = new Outer();
		Inner inner = otr.getInnerBuild();
		inner.dis();
	}
};

匿名内部类的创建

使用匿名内部类可以更进一步缩短内部类。因为匿名内部类主要用来创建Java事件的适配器,在Android的事件课程会具体讲解。
一个类在整个操作中只使用一次的话,就可以将其定义成匿名内部类,匿名内部类是在抽象类及接口的基础上发展起来的。
interface A{ public void printInfo() ; //
}

class B implements A{  //  实现接口 
  public void printInfo(){ 
    System.out.println("Hello World!!!") ; 
  } 
}

class X { 
  public void fun1(){ 
	      this.fun2(new B()) ; 
  } 
  public void fun2(A a){ 
    a.printInfo() ; 
  } 
}

public class NoInnerClassDemo01{ 
  public static void main(String args[]){ 
    new X().fun1() ;    //  实例化X 类的对象,并调用 fun1()方法 
  } 
}

更改为匿名内部类
interface A{ 
  public void printInfo() ;  //   
} 
class X { 
  public void fun1(){ 
    this.fun2(new A(){ 
        public void printInfo(){ 
          System.out.println("Hello World!!!") ; 
        } 
      } 
      )
  } 
  public void fun2(A a){ 
    a.printInfo() ; 
  } 
}
public class NoInnerClassDemo02{ 
  public static void main(String args[]){ 
    new X().fun1() ;    //  实例化X 类的对象,并调用 fun1()方法 
  } 
}

函数内部类的创建
我们除可建成员内部类外,还可以创建函数内部类,就是把内部类定义在函数里。
private String[] splitDt(String name) { class Inner { String name; Inner(String name) { this.name = name; }

				String[] getSplit() {
					return name.split("\\\\");
				}
			};
			return new Inner(name).getSplit();
		}

因函数的封装,也必须满足一般函数的封装特性。

class Outer{    //  定义外部类 
  private String info = "hello world" ;  //  定义外部类的私有属性 
  public void fun(final int temp){    //  定义外部类的方法 
    class Inner{            //  在方法中定义的内部类 
      public void print(){        //  定义内部类的方法 
        System.out.println("类中的属性:" + info) ;  //直接访问外部类的私有属性 
        System.out.println("方法中的参数:" + temp) ; 
      } 
    }; 
    new Inner().print() ;        //  通过内部类的实例化对象调用方法 
  } 
}
public class InnerClassDemo05{ 
  public static void main(String args[]){ 
    new Outer().fun(30) ;  //  调用外部类的方法 
  } 
}

函数内部类创建,错误示项
内部类不能加任何封装操作符
一个内部类可以在任意的位置上定义。
内部类的方法在接收参数时,必须在参数类型定义前添加 final 关键字。
java中规定,内部类只能访问外部类中的成员变量,不能访问方法中定义的变量,如果要访问方法中的变量,就要把方法中的变量声明为final(常量)的,因为这样可以使变量全局化,就相当于是在外部定义的而不是在方法里定义的
private String[] splitDt(final String name) { // 错误,不能加封装 int i=100; public class Inner {

				String[] getSplit() {
					System.out.println(i);
					return name.split("\\\\");
				}
			};
			return new Inner().getSplit();
		}

成员内部类是否可以多态

class SuperFather {
	class Inner {
		void show() {
			System.out.println(“父类SuperFather中,内部类多态测试");
		}
	}

	Inner getInnerBuild() {
		return new Inner();
	}
}

public class Outer extends SuperFather {
	int outer_i = 66;

	class Inner {
		void show() {
			System.out.println("子类Outer中,内部类覆盖");
		}
	}

	Inner getInnerBuild() {
		return new Inner();
	}

	public static void main(String[] args) {
		SuperFather father = new Outer();//不能向上转换
		father.getInnerBuild().show();
	}
}

枚举类型简介 在JDK1.5 之前,Java 可以有两种方式定义新类型:类和接口。对于大部分面向对象编程来说,这两种方法看起来似乎足够了。但是在一些特殊情况下,这些方法就不适合

例如:想定义一个 Colour 类,它只能有 Red、Green 和Blue 三种值,其他的任何值都是非法的。
通过private将构造器隐藏起来
把这个类的所有可能实例都使用public static final属性来保存
如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配实例。
那么JDK1.5 之前虽然可以构造这样的代码,但是要做很多的工作,也有可能带来各种不安全的问题。而 JDK1.5 之后引入的枚举类型(enum)就能避免这些问题。 
class Color{ public static final Color RED = new Color(“红色”) ; // 定义第一个对象 public static final Color GREEN = new Color(“绿色”) ; // 定义第一个对象 public static final Color BLUE = new Color(“蓝色”) ; // 定义第一个对象 private String name ; private Color(String name){ this.name = name ; } public void setName(String name){ this.name = name ; } public String getName(){ return this.name ; } public static Color getInstance(int i){ switch(i){ case 1:{ return RED ; } case 2:{ return GREEN ; } case 3:{ return BLUE ; }default:{ return null ; } } }

}

定义一个枚举类型

所谓的枚举就是规定好了制定的取值范围,所有的内容只能从指定的范围中取得。 
在JDK1.5 之后,引入了一个新的关键字类型——enum,可以直接定义枚举类型,格式如下:
[public] enum 枚举类型名称{ 枚举对象 1, 枚举对象 2, …… 枚举对象 n; }

枚举使****用
枚举已经指定好了范围,所以可以使用 foreach 进行全部的输出,使用“枚举.values()”的形式取得全部的枚举内容。 
还可以直接将内容在上 witch 语句上使用。 

Enum 类 

使用 enum 声明的枚举类型,就相当于定义一个类,而此类则默认继承 java.lang.Enum 类。 
java.lang.Enum 类的定义如下: 

public abstract class Enumextends Object implements Comparable,Serializable

此类定义的时候使用了泛型机制,而且实现了 Comparable 接口以及Serializable 接口,证明此种类型是可以比较,可以被序列化的。 

Enum 类的构造方法: 
protected Enum(String name,int ordinal)

构造方法中接收两个参数,一个表示枚举的名字,另外一个表示枚举的序号。

常用方法:

对象与垃圾回收  Java的垃圾回收是Java语言的重要功能之一。当程序创建对象,数组等引用类型实体时,系统都会在堆内存中为之分配一块内存区,对象就保存在这块内存区中,当这块内存不再被任何引用变量引用时,这块内存就变成垃圾,等待垃圾回收机制进行回收。

垃圾回收机制特点

垃圾回收机制只负责堆内存中对象,不会回收任何物理资源(网络、IO等资源)
程序无法精确控制垃圾回收的运行,垃圾回收会在适合适合进行。
垃圾回收机制回收任何对象之前,总会先调用它的finalize方法,该方法可以使该对象重新复活,从而导致垃圾回收机制取消回收。

对象与垃圾回收

对象所处的状态
激活状态
去活状态
死亡状态

Finalize方法

当垃圾回收机制回收某个对象所占用的内存之前,通常要求程序调用适当的方法来清理资源,在没有明确指定资源清理的情况下,java提供了默认机制来清理该对象的资源,这个方法就是finalize,该方法是定义在Object类的实例方法,方法原型为:
protected void finalize() throws Throwable

finalize方法特点

永远不要主动调用某个对象的finalize方法,该方法应交给垃圾回收机制调用
finalize方法何时被调用,是否被调用具有不确定性。
当jvm执行去活对象的finalize方法是,可能是该对象或者系统中其他对象重新变成激活状态
当jvm执行finalize方法时出现了异常,垃圾回收机制不会报告异常,程序继续执行。

通知垃圾回收器进行垃圾回收:
方法一  调用System类的gc()静态方法System.gc()
方法二 调用Runtime对象gc()实例方法:Runtime.getRuntime().gc();

使用Java 命令-verbose:gc来运行可以查看每次垃圾回收以后的提示信息

强制系统进行垃圾回收
System和Runtime类里都提供了一个runFinalization方法,可以强制垃圾回收机制调用系统中去活对象的finalize方法。

问题1~4的答案:

1.Final和abstract永远不能同时使用修饰类或者方法。

2.Static和abstract不能同时修饰某个方法,即没有所谓的类抽象方法。Abstract不能用于修饰属性,不能用于修饰局部变量,即没有抽象变量,没有抽象属性。Abstract不能修饰构造器,没有抽象构造器

3.一个抽象类中是存在构造方法的。因为抽象类依然使用的是类的继承关系,而且抽象类中也存在各个属性,所以子类在实例化之前肯定是先要对父类进行实例化的。也可以通过super 明确的指定要调用的构造方法。

4.抽象类使用的时候一定要有子类,子类仍然使用 extends 关键字继承一   个抽象类,同样会存在单继承的限制。即:一个子类不能同时集成多个抽象类。

收藏

暂无评论

登录后可以进行评论。没有账号?马上注册