第十七篇 黑马程序员-Java高新技术

------- android培训java培训、期待与您交流! ----------

一:
1.可变参数:

一个方法接受的的参数个数不固定,例如:
System.out.println(add(2,3,5));
System.out.println(add(1,2,3,4));

2.可变参数的特点:

只能出现在参数列表的最后;
...位于变量类型和变量名之间,前后有无空格都可以;
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中用数组的形式访问可变参数;

3.for的增强循环

格式:for(type 变量名:集合变量名){...}

4.注意事项:
迭代变量必须在()中定义
集合变量可以是数组或实现了Iterable接口的集合类

5.享元模式(flyweight):
如果有很多很小的对象,他们有很多相同的属性,那你就可以把他们变成一个对象,还有些不同的属性,
把他们变成方法的参数,称之为外部状态,那些相同的属性称之为这个对象的内部状态。

枚举:
用普通类模仿枚举:
package cn.itcast.day1;

public class EnumTest {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  /**
   * 这里在赋值时,只能调用类WeekDay里面的这些常量
   * 这里MON这个常量是一个对象,是WeekDay里面的这种类型的对象,所以
   * 我们可以给它赋值,赋给WeekDay这种类型的引用变量weekDay,而且只能
   * 赋在类WeekDay里面定义的常量,这就是枚举。
   * */
  WeekDay weekDay=WeekDay.MON;
  System.out.println(weekDay.nextDay());
  

 }

}

package cn.itcast.day1;
/**
 * 用普通类模仿枚举
 * 类WeekDay创建的实例对象是我规定的那么几个,首先,把构造方法定义成
 * 私有的,人家不能创建了,
 * */
public class WeekDay {
 private WeekDay(){}
 
 public final static WeekDay SUN=new WeekDay();
 public final static WeekDay MON=new WeekDay();
 
 //此方法不要定义成静态的,这是SUN这些实实在在的对象上的方法(注意:静态修饰内容被对象所共享)。
 public WeekDay nextDay(){
  if(this==SUN){//假如当前对象等于SUN这个引用变量指向的对象
   return MON;
  }else{
   return SUN;
   
  }
 }
 //这里覆盖toString方法,打印诸如SUN这些东东
 public String toString(){
  return this==SUN?"SUN":"MON";
  
 }


}
这里的SUN等是对象类型的。这在枚举里就是一个对象,每一个枚举元素都是一个对象
此外,还有一种实现方式:
将SUN等这些的nextDay都用一个独立的方法去写,现在我要每个元素自己写自己的方法:
package cn.itcast.day1;
/**
 * 用普通类模仿枚举
 * 类WeekDay创建的实例对象是我规定的那么几个,首先,把构造方法定义成
 * 私有的,人家不能创建了,
 * */
public abstract class WeekDay2{
 private WeekDay2(){}
 
 //此类是WeekDay的子类,并且用这个子类创建了一个对象
 public final static WeekDay2 SUN=new WeekDay2(){
  

  @Override
  /**
   * 抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,
   * 建立子类对象调用。
   * */
  public WeekDay2 nextDay() {
   // TODO Auto-generated method stub
   return MON;
  }
  
 };
 public final static WeekDay2 MON=new WeekDay2(){

  @Override
  public WeekDay2 nextDay() {
   // TODO Auto-generated method stub
   return SUN;
  }};
 
 public abstract WeekDay2 nextDay();
 
 //此方法不要定义成静态的,这是SUN这些实实在在的对象上的方法(注意:静态修饰内容被对象所共享)。
 /*public WeekDay2 nextDay(){
  if(this==SUN){//假如当前对象等于SUN这个引用变量指向的对象
   return MON;
  }else{
   return SUN;
   
  }
 }*/
 
 
 //这里覆盖toString方法,打印诸如SUN这些东东
 public String toString(){
  return this==SUN?"SUN":"MON";
  
 }


}

package cn.itcast.day1;

public class EnumTest2 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  /**
   * 这里在赋值时,只能调用类WeekDay里面的这些常量
   * 这里MON这个常量是一个对象,是WeekDay里面的这种类型的对象,所以
   * 我们可以给它赋值,赋给WeekDay这种类型的引用变量weekDay,而且只能
   * 赋在类WeekDay里面定义的常量,这就是枚举。
   * */
  WeekDay2 weekDay=WeekDay2.MON;
  System.out.println(weekDay.nextDay());
  

 }

}
采用抽象方法定义nextDay就将大量的if...else语句转移成了一个个独立的类。
枚举自动可以帮我们实现toString方法。
枚举的基本应用:
枚举里面的方法:
代码演示:
package cn.itcast.day1;

public class EnumTest3 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  /**
   * 这里在赋值时,只能调用类WeekDay里面的这些常量
   * 这里MON这个常量是一个对象,是WeekDay里面的这种类型的对象,所以
   * 我们可以给它赋值,赋给WeekDay这种类型的引用变量weekDay,而且只能
   * 赋在类WeekDay里面定义的常量,这就是枚举。
   * */
  WeekDay3 weekDay=WeekDay3.MON;
  System.out.println(weekDay.nextDay());
  //这里定义变量的时候就只能给它枚举WeekDay里面定义的元素,这里FRI是一个对象
  WeekDay weekDay2=WeekDay.FRI;
  System.out.println(weekDay2);
  System.out.println(weekDay2.name());
  System.out.println(weekDay2.ordinal());
  System.out.println(WeekDay.valueOf("SUN").toString());
  System.out.println(WeekDay.values().length);
  

 }
 //枚举WeekDay相当于一个对象,而里面的SUN等就是一些实例对象
 public enum WeekDay{
  SUN,MON,TUE,WED,THI,FRI,SAT
 }

}

package cn.itcast.day1;
/**
 * 用普通类模仿枚举
 * 类WeekDay创建的实例对象是我规定的那么几个,首先,把构造方法定义成
 * 私有的,人家不能创建了,
 * */
public abstract class WeekDay3{
 private WeekDay3(){}
 
 //此类是WeekDay的匿名子类,并且用这个子类创建了一个对象
 public final static WeekDay3 SUN=new WeekDay3(){
  

  @Override
  /**
   * 抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,
   * 建立子类对象调用。
   * */
  public WeekDay3 nextDay() {
   // TODO Auto-generated method stub
   return MON;
  }
  
 };
 public final static WeekDay3 MON=new WeekDay3(){

  @Override
  public WeekDay3 nextDay() {
   // TODO Auto-generated method stub
   return SUN;
  }};
 
 public abstract WeekDay3 nextDay();
 
 //此方法不要定义成静态的,这是SUN这些实实在在的对象上的方法(注意:静态修饰内容被对象所共享)。
 /*public WeekDay2 nextDay(){
  if(this==SUN){//假如当前对象等于SUN这个引用变量指向的对象
   return MON;
  }else{
   return SUN;
   
  }
 }*/
 
 
 //这里覆盖toString方法,打印诸如SUN这些东东
 public String toString(){
  return this==SUN?"SUN":"MON";
  
 }


}
打印结果是:
SUN
FRI
FRI
5
SUN
7

name()
ordinal()
表示元素在枚举里面是第几个
valueOf()
把元素装换成枚举里面的元素对象。如把System.out.println(WeekDay.valueOf("SUN").toString());
里面的“SUN”转换成枚举里面的元素SUN.即把一个字符串变成所对应的枚举元素。
values():
返回一个数组,也就是说把这个枚举里面的每个元素一个个逐一装进这个数组看里面,我们什么时候要用这个呢,当我们需要迭代这个枚举里面的所有元素,刚才学过for加强语句,我们要对枚举里面的元素逐一进行遍历,我们不能直接遍历这个枚举类,应该把得到枚举里所有元素的这个数组,再对这个数组进行遍历,这个方法就是把枚举里所有的元素转换成一个数组。
实现带有构造方法的枚举:
代码演示:
package cn.itcast.day1;
/*
 * 实现带有构造方法的枚举
*/
import cn.itcast.day1.EnumTest3.WeekDay;

public class EnumTest4 {

 /**
  * @param args
  */
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  /**
   * 这里在赋值时,只能调用类WeekDay里面的这些常量
   * 这里MON这个常量是一个对象,是WeekDay里面的这种类型的对象,所以
   * 我们可以给它赋值,赋给WeekDay这种类型的引用变量weekDay,而且只能
   * 赋在类WeekDay里面定义的常量,这就是枚举。
   * */
  WeekDay3 weekDay=WeekDay3.MON;
  System.out.println(weekDay.nextDay());
  //这里定义变量的时候就只能给它枚举WeekDay里面定义的元素,这里FRI是一个对象
  WeekDay weekDay2=WeekDay.FRI;
  System.out.println(weekDay2);
  System.out.println(weekDay2.name());
  System.out.println(weekDay2.ordinal());
  System.out.println(WeekDay.valueOf("SUN").toString());
  System.out.println(WeekDay.values().length);
  

 }
 //枚举WeekDay相当于一个对象,而里面的SUN等就是一些实例对象
 public enum WeekDay{
  SUN,MON,TUE,WED,THI,FRI,SAT;
  private WeekDay(){
   System.out.println("first");
  }
  private WeekDay(int day){
   System.out.println("second");
  }
 }

}

package cn.itcast.day1;
/**
 * 用普通类模仿枚举
 * 类WeekDay创建的实例对象是我规定的那么几个,首先,把构造方法定义成
 * 私有的,人家不能创建了,
 * */
public abstract class WeekDay4{
 private WeekDay4(){}
 
 //此类是WeekDay的匿名子类,并且用这个子类创建了一个对象
 public final static WeekDay4 SUN=new WeekDay4(){
  

  @Override
  /**
   * 抽象类中的方法要被使用,必须由子类复写所有的抽象方法后,
   * 建立子类对象调用。
   * */
  public WeekDay4 nextDay() {
   // TODO Auto-generated method stub
   return MON;
  }
  
 };
 public final static WeekDay4 MON=new WeekDay4(){

  @Override
  public WeekDay4 nextDay() {
   // TODO Auto-generated method stub
   return SUN;
  }};
 
 public abstract WeekDay4 nextDay();
 
 //此方法不要定义成静态的,这是SUN这些实实在在的对象上的方法(注意:静态修饰内容被对象所共享)。
 /*public WeekDay2 nextDay(){
  if(this==SUN){//假如当前对象等于SUN这个引用变量指向的对象
   return MON;
  }else{
   return SUN;
   
  }
 }*/
 
 
 //这里覆盖toString方法,打印诸如SUN这些东东
 public String toString(){
  return this==SUN?"SUN":"MON";
  
 }


}

打印结果是:
SUN
first
first
first
first
first
first
first
FRI
FRI
5
SUN
7
注意:枚举里面的元素必须位于所有成份之前只要用到了枚举类,它里面的静态变量都会被初始化,只要用到了类,它的静态代码都会被执行,这不用怀疑,此代码里面枚举里的元素等同于静态的成员变量,他们都会被执行,他们执行的时候构造方法被调用了,所以全是first.这是调用空参数的那个构造函数的缘故,如果我们想要其调用那个有参构造函数该怎么做呢,方法就是在元素的前面加个数值,比如在SUN前面加个1,就是SUN(1),那么打印结果就是,即先调用了有参构造函数,打印了一个second:
SUN
second
first
first
first
first
first
first
FRI
FRI
5
SUN
7
实现带有抽象方法的枚举:
注意:一个类的内部类可以用四个修饰符修饰,外部类只能用两个修饰符修饰,一个默认的,一个public,
这里这些内部类和这里的成员方法和成员变量都是用public修饰的是平级的,那成员变量和成员方法有什么它就有什么。他们是兄弟关系,都是放在类上面的.
注意:
new Date(300){};这段代码表示new了一个Date的子类,子类的构造方法是调用父类的无参构造方法
我希望子类的构造方法调用父类的有参构造方法,这里表示new一个Date的子类的实例对象,并且调用了父类的有参构造函数。
枚举只有一个成员时,就可以作为一种单例的实现方式。
为什么要使用枚举写单例呢,第一,构造方法不用再写了,默认的是私有的,不带参数的,new instance哪个代码也不用自己写了,因为那个元素自然的就new出来了,用枚举创建单例很简单的。

二.
反射的基石-Class类
如何得到各个字节码所对应的实例对象:
类名.class
对象.getClass
Class.forName(“类名”),比如Class.forName(“java.util.Date”)
九个预定义Class实例对象:
有八个基本数据类型,一个类型就对应一个实例对象。
一个void.
数组类型的Class实例对象
用到的方法就是Class.isArray()
反射就是把Java类中的各种成份映射成相应的Java类
构造方法反射的应用:
代码演示:
package cn.itcast.day1;

import java.lang.reflect.Constructor;

public class ReflectTest {
 public static void main(String[] args) throws Exception{
  String str1="abc";
  Class cls1=str1.getClass();
  Class cls2=String.class;
  Class cls3=Class.forName("java.lang.String");
  
  System.out.println(cls1==cls2);
  System.out.println(cls2==cls3);
  //判断是否是基本基本数据类型的方法
  System.out.println(cls1.isPrimitive());
  System.out.println(int.class.isPrimitive());
  System.out.println(int.class==Integer.class);
                //这里Integer.TYPE表示这个Integer为基本类型了
  System.out.println(int.class==Integer.TYPE);
  System.out.println(int[].class.isPrimitive());
  System.out.println(int[].class.isArray());
  
  /**
   * 这个StringBuffer是表示选择哪个构造方法。
   * 当得到一个构造方法,
   * 这里不知道是String类里面的哪个构造方法(这是在编译时,是不知道的),只知道你是一个
   * 构造方法,可以newInstance,要在运行阶段才会知道对应的构造方法
   * 这里一定要区分出运行时和编译时,这里运行时才执行
   * String.class.getConstructor(StringBuffer.class);这行代码
   * 所以在编译时是不知道这个构造方法属于的是哪个类
   * */
  Constructor constructor1=String.class.getConstructor(StringBuffer.class);
  /**
   * 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,
   * 并用指定的初始化参数初始化该实例
   * newInstance可以调用很多次,每调用一次就new一个新的String.
   * (new StringBuffer("abc")表示传一个StringBuffer的对象进去
   * 这里表示在用一个StringBuffer构造方法的时候在传一个对象进去
   *
   * */
  String str2=(String)constructor1.newInstance(new StringBuffer("abc"));
  System.out.println(str2.charAt(2));
  
 }
 
}
打印结果是:
true
true
false
true
false
true
false
true
c
这里得到一个构造方法,然后new一个Instance,这里用到反射。
Class.newInstance()方法:
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象。
该方法内部的具体代码是怎样呢?用到了缓存机制来保存默认构造方法的实例对象
这里的newInstance是Class里面的,也可以创建实例对象,这里的和构造方法里面的newInstance有什么区别没有,这里是一个无参的构造方法,表示为:public T newInstance()throws InstantiationException,是一个无参的构造方法,其实不要这个方法不影响Java的开发,但为什么要提供这样的一个方法呢?是提供一个便利,我们要创建一个类的实例对象的步骤是:由class得到constructor,再new Object,这样比较麻烦,而Class.newInstance可以把中间一步省略,即该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象,而构造方法里面的newInstance表示为:public T newInstance(Object... initargs)  throws InstantiationException,
反射的弊端:比较占用资源,导致程序性能下降                                               
注意:因为构造方法是无序的,所以我们想要得到某个类里面的一些构造方法,就必须根据构造方法的参数。
Constructor类:
Constructor类代表某个类中的一个构造方法。
例子:
得到某个类所有的构造方法:
Constructor[] constructors=Class.forNmae("java.lang.String").getConstructors();
得到某一个构造方法:
例子:
注意:获得方法时要用到类型
Constructor constructor=Class.forName("java.lang.String").getConstructor(StringBuffer.class);
创建实例对象:
注意:调用获得的方法时要用到与上面相同类型的实例对象
String str=(String)constructor.newInstance(new StringBuffer("abc"));
成员变量的反射:
代码演示:
package cn.itcast.day1;

public class ReflectPoint {
 private int x;
 public int y;
 public ReflectPoint(int x, int y) {
  super();
  this.x = x;
  this.y = y;
 }

}

package cn.itcast.day1;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class ReflectTest2 {
 public static void main(String[] args) throws Exception{
               ReflectPoint pt1=new ReflectPoint(3,5);
  /**
   *这里先得到字节码,因为字节码有字段信息,再得到某个字段,
   *类上有很多字段,即有很多成员变量,用变量名来区别
   *这里的fieldY的值不是5,这里的fieldY只是代表这个类
   *的字节码的一个变量。它没有对应到对象身上,我可以用pt1,pt2或
   *pt3等搞出很多个对象,每个对象身上都有一个fieldY,这个fieldY
   *在pt1上是5,在pt2上就不知道是多少了,就是说fieldY不代表一个
   *具体的值,只代表一个变量,即不代表某个变量身上具体的值.
   *举个例子:在Person类中,有对象张三,李四,王五,他们每个人都只有
   *一个苹果,假如这些苹果是编号的,张三等他们也是编号的,是不同的对象
   *我把这些编号的苹果给他们,我不知道第几号苹果属于他们其中哪个,
   *有可能张三,李四都有一个编号为1的苹果,这里的fieldY就代表这些编号的苹果,
   *要想得到其中一个人所持有的苹果的编号值,那么就要找到这个具体的
   *人,然后得到苹果查看编号
   *
   * */
  Field fieldY=pt1.getClass().getField("y");
  //取出变量上的值
  System.out.println(fieldY.get(pt1));
  /**
   * getDeclaredField()方法设置私有可见,这里x就是私有的
   * */
  Field fieldX=pt1.getClass().getDeclaredField("x");
  //设置可以访问
  fieldX.setAccessible(true);
  System.out.println(fieldX.get(pt1));
  
 }
 
}
打印结果是:
true
true
false
true
false
true
false
true
c
5
3

Field类:
Field类代表某个类中的一个成员变量
按ALT+Shift+S快捷键是创建构造方法。
成员方法的反射:
代码演示:
package cn.itcast.day1;
/**
 * 方法的反射
 * */
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectTest3{
 public static void main(String[] args) throws Exception{
  String str1="abc";
                /**
   * name:方法名   
   * int.class:一个类里面同一个名字的方法有多种重载形式,那怎样从这些方法中选取一个呢
   * 那就要靠方法的参数列表,参数列表就包括了参数类型和参数个数,这里的每一个参数类型都用一
   * 个class来表示,到底有多少个参数就在这里写多少个class进去,我们这里只有一个参数,而charAt是
   * int,所以这里写成int.class.
   * */
  
  Method methodCharAt=String.class.getMethod("charAt", int.class);
  System.out.println(methodCharAt.invoke(str1, 1));
 }
 
}
打印结果是:
b
这里是用反射的方式获得字节码里的方法,再拿这个方法作用于这个对象,invoke方法就是调用这个方法的意思,chatAt方法执行调用的动作。即这个invoke是这个methodCharAt方法对象身上的方法。
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子:
Method charAt=Class.forName("java.lang.String").getMethod("charAt",int.class);
调用方法:
通常方式:
System.out.println(str.charAt(1));
反射方式:
注意:
如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法。
System.out.println(charAt.invoke(str,1));
jdk1.4和jdk1.5的invoke方法的区别:
jdk1.5:public Object invoke(Object obj,Object...args)
jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组
作为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用chatAt方法的代码也可以用
jdk1.4改写为charAt.invoke("str",new Object[]{1}形式。

 

------- android培训java培训、期待与您交流! ----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值