黑马程序员:java加强笔记(上)

----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

常见英文缩写的意思:

ide——>itegrated development environment

静态导入:JDK1.5

import static java.lang.Math.max;

import static java.lang.Math.*;如此导入之后写静态方法的时候可以不用写类名

overload  vs  override

重载:方法名字相同,但是方法不能完全相同,要求参数,返回值应该有不同,但是不能只是返回值不同

重写:父类的私有方法是不能重写的,子类出现的相同方法也只算是自己的特有方法。

可变参数:一个方法接受的参数个数不确定

以数组的形式使用

public static int add(int x,int...args){

int sum=0;

for(int i=0;i<args.length;i++)

{sum+=args[i];}

}

可变参数的特点:

1,只能出现在参数列表的最后;

2...位于变量类型和变量名之间,前后又无空格均可

3,调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数

增强for循环:

for(type 变量名集合变量名){}

public static int add(int x,int...args){

int sum=0;

for(int x:args){

sum+=arg;

}

return sum;

}

迭代变量必须在()之中定义,集合变量可以是数组或者是实现了Iterable接口的集合类

迭代变量类型之前可以加修饰符,比如final

基本数据类型的自动拆箱&自动装箱:JDK1.5

Integer i1=127;

Integer i2=127;//i1==i2——true

Integer i3=128;

Integer i4=128;//i3==i4——false

-128~127范围内的Integer对象是唯一的(一个字节之内),因为常用,而且占用内存少,所以单独唯一定义。为了公用

————————享元模式!——flyweight

那些定义成相同对象的称为内部状态,经常不同的要从外部传入的称为外部状态

有很小对象有很多相同的属性,把这些对象封装成一个固定对象,不同的属性通过外部传入。

枚举:JDK1.5

枚举就是让某个类型的变量的取值只能从若干个规定值中的一个,否则编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中天蝎的非法制,普通变量的方式在开发阶段无法实现这一目标;

枚举元素都是一个对象,

用普通类实现枚举功能,定义一个WeekDay

1,私有构造方法

2,每个元素分别用一个工友的静态成员变量表示

3,可以有若干共有方法或抽象方法,例如提供nextDay方法必须是抽象的

class abstract WeekDay(){

private WeekDay(){}

public final static WeekDay SUN=new WeekDay(){

public WeekDay nextDay(){

return MON;

}

};

public final static WeekDay MON=new WeekDay(){

public WeekDay nextDay(){

return SUN;

}

};

abstract WeekDay nextDay();//转的方式就是在父类中定义一个抽象方法

//在子类对象之中实现他,如上例

/*//把大量的if-else语句转给一个个子类

public WeekDay nextDay(){

if(this=SUN){return MON};

else(return SUN};

}

*/

public String toString(){

return this==SUN?"SUN":"MON";

}

}

基本应用:

枚举类的values:把枚举封装成数组,是静态方法

valueOf:把字符串封装成枚举对象

name:获取字符串表达形式

toString

ordinal:获取该元素在枚举中的顺序

public enum WeekDay{

SUN,MON,TUE,WED,THU,FRI,SAT;

}

总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,

可以调用WeekDay.SUN.getClass().getName()WeekDay.class.getName()

如果想在一个类之中使用一个枚举类,可以把枚举类定义成内部类。

枚举之中的构造函数必须放在元素列表之后,而且必须是私有的。

用到枚举类的时候,静态的成员变量都会被初始化;初始化的时候,默认使用的无参数的构造函数,如果要指定有参数的构造函数可以参数后括号来指定

外部类可以有publicdefault,内部类可以有4个修饰符+privateprotected

枚举只有一个成员时,就可以作为一种单例的实现方式

反射:

Class——所有的直接图纸,所有直接造对象的图纸是一个类

java程序中的各个java类属于同一种事物,描述这类事物的java类名就是Class

都是对事物的描述——同一个类

众多的人用一个类描述——Person

众多的java类用一个类描述——Class

Class代表一类什么样的事物?————字节码

Class class1=Date.class//Date类的字节码

Class 类的实例表示正在运行的 Java 应用程序中的类和接口

Person p=new Person();

p.getClass();

Class.forName("java.lang.String");//返回字节码,被加载过,直接返回;没加载过,先加载进JVM,再返回,以后就不用加载

获取对应字节码Class对象的三种方法:

类名.class

对象.getClass()

Class.forName("类名的字符串变量"),如,Class.forName("java.util.Date")

九个预定义的Class实例对象:

八个自定义类型加上voidvoid.class

基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象

public boolean isPrimitive()

判定指定的 Class 对象是否表示一个基本类型。 

有九种预定义的 Class 对象,表示八个基本类型和 void。这些类对象由 Java 虚拟机创建,与其表示的基本类型同名,即 booleanbytecharshortintlongfloat 和 double

这些对象仅能通过下列声明为 public static final 的变量访问,也是使此方法返回 true 的仅有的几个 Class 对象。

int.class==Integer.TYPE;————TYPE代表包装类型所包装的基本类型的字节码

数组类型的Class实例对象

Class.isArray();

int[].class.isArray()==true;

总之,在程序中出现的所有类型都各自的Class实例对象字节码

任何类型都对应一个字节码,都对应一个.class文件

反射:

JAVA反射机制: 

JAVA反射机制定义:  JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 

Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言

尽管在这样的定义与分类下Java不是动态语言,它却有着一个非常突出的动态相关机制:Reflection。这个字的意思是反射、映象、倒影,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。这种看透class的能力(the ability of the program to examine itself)被称为introspection(内省、内观、反省)。Reflectionintrospection是常被并提的两个术语。 

类的生命周期:

在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。

类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前

链接就是把二进制数据组装为可以运行的状态。

 

链接分为校验,准备,解析这3个阶段

校验一般用来确认此二进制文件是否适合当前的JVM(版本),

准备就是为静态成员分配内存空间,。并设置默认值

解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)

完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。

当没有任何引用指向Class对象时就会被卸载,结束类的生命周期

java类就是把Java类中所有的成分用类来表示(映射成相应的java类)

如:一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的java类来表示;

就像汽车是一个类,汽车中的发动机,变速箱等等也是一个个的类。

表示java类的Class类显然要提供一系列的方法,来获取其中的变量,方法,构造方法,修饰符,包等信息,这些信息就是用相应类的实例对象来表示,他们是FieldMethodConstructorPackage等等

一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示,通过调研Class的方法可以得到这些实例对象。这些对象有什么用,怎么用?这就是反射要解决的问题

l Constructor

代表某个类中的一个构造方法。

Constructor constructor1=String.class.getConstructor(StringBuffer.class,int.class)

——代表参数是StringBufferint的构造函数

——这里方法的定义用的是可变参数(JDK1.5新特性)

String str=(String)constructor1.newInstance(new StringBuffer("abc"));

——编译时期只知道是构造方法,但是不知道是什么样的构造方法,也不知道是谁的构造方法。所以需要在前面加上(String)来强制转换,其方法定义的时候返回的是Object类型。——???能泛型吗???

如果这时候参数传入"abc":

(String)constructor1.newInstance("abc");——编译没问题,运行出错

创建一个类的实例对象的步骤:class——constructor——new object

ClassnewInstance()方法:内部封装了constructor无参数的构造方法

如同用一个带有一个空参数列表的 new 表达式实例化该类

得到构造方法,然后缓存起来,反射会导致性能下降,计算机每次加载构造方法很费时

l Field

import java.lang.reflect.Field;

public class ChangeClassField {

/**

 * @param args

 * @throws ReflectiveOperationException 

 * @throws IllegalArgumentException 

 */

public static void main(String[] args) throws IllegalArgumentException, ReflectiveOperationException {

// TODO Auto-generated method stub

//扫描所有字段,改掉字母‘b’

//反射的作用:在运行时改变类的内容

ReflectionPoint pt=new ReflectionPoint(3, 5);

System.out.println(pt);

changeStringValue(pt);

System.out.println(pt);

}

private static void changeStringValue(ReflectionPoint pt) throws IllegalArgumentException, ReflectiveOperationException {

// TODO Auto-generated method stub

Field[] fs=pt.getClass().getFields();

for(Field f:fs){

if(f.getType()==String.class){//字节码是唯一的,所以用==比equals好

String oldValue=(String)f.get(pt);

String newValue=oldValue.replaceAll("b""BBBBB");

f.set(pt, newValue);

}

}

}

l Method

package it.cast.reflection;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

public class MethodDemo {

/**

 * @param args

 * @throws SecurityException 

 * @throws NoSuchMethodException 

 * @throws InvocationTargetException 

 * @throws IllegalArgumentException 

 * @throws IllegalAccessException 

 */

public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

// TODO Auto-generated method stub

String str="abcd";

Method methodCharAt=String.class.getMethod("charAt"int.class);//charAt方法的对象

System.out.println(methodCharAt.invoke(str, 2));//charAt方法的对象调用自己所代表的方法

}

}

静态方法调用的时候不需要对象,所以invoke(null,每个参数的class)就是第一个写对象的地方写上null

JDK1.5有可变参数:Object.invoke(obj,Object...args)

JDK1.4没有可变参数,用参数数组:Object.invoke(obj,Object[] args)

用反射方式来调用另外一个类里面的main方法:

不知道要执行哪一个类的main方法,可以作为变量传入

String className=args[0];

Method mainMethod=Class.forName(className).getMethod("main",String[].class);

JDK1.5为了跟JDK1.4兼容,会把传给main的字符串数组打开,把里面的元素个数作为参数的个数。可以把这个数组再次包装起来

mainMethod.invoke(null,new String[]{"111","222"});

变成:mainMethod.invoke(null,new Object[]{new String[]{"111","222"}});

或者:mainMethod.invoke(null,(Object)new String[]{"111","222"});

String className=args[0];//把要调用的类的名称通过自己的主函数参数传递进来

Method mainMethod=Class.forName(className).getMethod("main",String[].class);

mainMethod.invoke(null,new Object[]{new String[]{"111","222"}});

l Class Array数组反射

???数组是对象,父类是Object???

数组只要类型和维数一样就是一样的.class文件

new int[2].getClass().getSuperclass().getName();得到数组的父类

Object objs=new int[2];可以

Object[] objs=new int[1][2];可以

Object[] objs=new int[2];不可以,int不是Object

数组是没办法得到数组的类型的,只能得到具体元素的类型

Object[] a=new Object[]{"asda",1};

a[0].getClass().getName();

数组反射的应用:

Class cls=obj.getClass();

if(cls.isArray()){

int len=Array.getLength(obj);

for(int i=0;i<len;i++){

System.out.println(Array.get(obj, i));

}

}

else

System.out.println(obj);

l ArrayListHashSetHashCode

ArrayList的数据结构是可变长度的数组,可以有相同元素

HashSet的数据结构是哈希表,是不允许相同元素存在的,元素是否相同依靠HashCode()方法和equals()方法来判断。

HashCode()方法:

如下例子:HashSet hs=new HashSet();

ReflectionPoint pt1=new ReflectionPoint(3,4);

ReflectionPoint pt2=new ReflectionPoint(4,4); 

ReflectionPoint pt3=new ReflectionPoint(3,5); 

hs.add(pt1);

hs.add(pt2);

hs.add(pt3);

pt1.y=7;

hs.remove(pt1);

pt1存入的时候hashCode值跟要删除的时候pt1hashCode是不一样的,所以删除的时候去新的hashCode所表示的存储空间找,结果没找到原来的pt1,所以删除失败。

所以最后元素个数还是3个!

这种情况经常发生的话,很容易造成内存泄露!有的东西一直在内存,但是不会被使用,长久下去就会造成内存泄露!

反射的作用——实现框架的功能

框架

我做房子给用户住,用户自己安装门窗,空调!我做的这个房子就是框架!用户需要适使用我的框架,把门窗插入进我提供的框架中。

框架与工具类有区别,工具类被用户的类调用,而框架则是调用用户提供的类。

框架要解决的核心问题

我在打框架(房子)的时候,用户还不确定,可能这个用户还没出生!我的框架怎样调用用户以后写的类(门窗)呢?

因为在写程序的时候无法知道被调用的类名,所以在程序中无法直接new某个类的实例对象,这就需要反射来完成!

把具体的类放在配置文件里面!

配置文件的路径需要用classpath指定

getRealPath();

一定要记住完整的路径,但完整的路径不是硬编码,而是运算出来

传入的字符串是完整的绝对路径加上内部路径

另外一个方法:类加载器——只读,不怎么改动

Person.class.getClassLoader().getResourceAsAtream(name);

Person.class.getClassLoader().

getResourceAsAtream("cn/itcast/day1");

Class对象提供的方法:内部是用加载器加载的

Person.class.getResourceAsStream("绝对或者相对路径");

l IntroSpector——JAVAbean——>特殊的java

int getAge()

void setAge(int age)

具有上述方法的类可以作为javabean来操作!

如果把类作为javabean来看,其属性名称是依靠setget方法来确定的:因为属性是私有的,这个变量定义成什么名字无所谓;但是外部调用的时候能看到的是在操作age属性,所以就是操作age,而跟具体定义无关!

如果getAge()——age

settime——time

getTime——time:如果操作的属性,第二个字母是小写,则把第一个字母也小写

getCPU——CPU:如果全部大写,则属性也大写

————为了好看

l 如果要在两个模块之间传递多个信息,可以将这些信息封装到一个javabean中,这种javabean的实例对象通常称之为值对象(Value ObjectVO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问!javabean的属性是根据其中的settergetter方法来确定的,而不是根据其中的成员变量。

总之,一个类被当做javabean使用时,javabean的属性是根据方法名推断出来的,根本看不到java类内部的成员变量。

l 符合javabean特点的类可以作为普通类一样使用,但是作为javabean可以带来额外的好处:

1,在javaEE开发中,经常要使用到javabean,很多环节就要去按javabean方式进行操作,环境要求还有多数选择!

2JDk中提供了对javabean进行操作的一些API,这套API就称为内省。

l 内省操作实例

age——Age——getAge——MethodGetAge

只读——只有get方法

只写——只有set方法

PropertyDescriptor简单应用:

public static void main(String[] args) throws Exception {

ReflectionPoint pt=new ReflectionPoint(3, 5);

String propertyName="x";

Object retVal=getProperty(pt, propertyName);

System.out.println(retVal);

Object value=6;

setProperty(propertyName,pt,value);

System.out.println(pt.getX());

}

public static void setProperty(String propertyName,Object pt,Object value)

throws IllegalAccessException, InvocationTargetException, IntrospectionException {

PropertyDescriptor pd= new PropertyDescriptor(propertyName, pt.getClass());

Method methodSetX=pd.getWriteMethod();

methodSetX.invoke(pt, value);

}

public static Object getProperty(Object pt,

String propertyName) throws IntrospectionException,

IllegalAccessException, InvocationTargetException {

PropertyDescriptor pd= new PropertyDescriptor(propertyName, pt.getClass());

Method methodGetX=pd.getReadMethod();

return methodGetX.invoke(pt);

}

BeanInfo的应用:太麻烦!!!——getX()

BeanInfo beanInfo=IntroSpector.getBeanInfo(pt.getClass());

PropertyDescriptor[] pds=beanInfo.getPropertyDescriptors();

Object retVal=null;

for(PropertyDescriptor pd:pds){

if(pd.getName().equals(propertyName)){

Method methodGetX=pd.getReadMethod();

retVal=methodGetX.invoke(pt);

break;

}

}

return retVal;

l BeanUtils工具包——apache的开源工具包

添加到工程里面,添加到工程里面,然后buildpath,变成小奶瓶

还需添加日志包logging,同上步骤

以字符串写入属性名,以字符串返回结果:——自动进行字符串转换

BeanUtils.getProperty(pt,"x");

BeanUtils.setProperty(pt,"x","9");

网页上往往是操作字符串!

javabean可以跟map之间互转,通过BeanUtils完成,BeanUtils也可以操作Map;

PropertyUtils是用属性自己的类型来操作,得到的也是自己本来的类型

不一定是字符串,跟BeanUtils不一样;

注解——JDK1.5的新特性(枚举+注解两大新特性)

l Annotation一个注解就是一个类:加上注解,就相当于加上了一种标记,向工具软件传达一种信息。有了标记之后,javac编译器,开发工具和其它程序可以用反射来了解你的类及各种元素上有无何种标记,用什么标记就和做相应的事。

l 标记可以用在包,类,字段,方法,方法的参数以及局部变量上

l JDK,java.lang包中提供的最基本的annotation

l 具体注解

1,用@deprecated来标注要过时的方法,标注之后,对原来的老程序没有影响,但是对后来的程序,如果要调用这个方法会给出提示!

2,如果不想被提示,可以用压缩警告@SuppressWarnings("deprecation")来标示

3,@Override重载必须一模一样,特别是参数列表,

这时候加上注解,是不是覆盖就会有提示

l 注解的返回值只能是:8个基本类型,String,Class,enum,annotation以及其数组;

l 注解的应用:

注解类:

@interface A{}

应用注解类的类:

@A

class B{}

对应用了注解类的类进行反射操作的类:

Class C{

B.class.isAnnotionPresent(A.class);

A a=B.class.getAnnotion(A.class);

}

l 注解使用实例:

元注解:注解的注解

元数据:

元信息:信息的信息

编译的时候,javac可能会把注解去掉,所以使用的时候可能找不到

class文件中的内容不是字节码,只有用class的时候把内容加载(类加载器)到内存中,加载完之后会内容进行处理,安全检查等,处理完之后内存中的内容才是字节码(程序中的.class)

编译器是用二进制码来完成一些检查的!

注解的生命周期:java源文件——>class文件——>内存中的字节码

分别跟元注解@Retention的三种取值对应:

RetentionPolicy.SOURCE——java源文件

RetentionPolicy.CLASS——class文件————>默认值是CLASS阶段

RetentionPolicy.RUNTIME——内存中的字节码

(枚举)

@Override:value=SOURCE

@SuppressWarnings:value=SOURCE

@Deprecated:value=RUNTIME

元注解@Target(ElementType.METHOD,ElementType.TYPE)用来限定注解使用的场景:方法  注解  类  方法

@Override:的Target是METHOD(这是ElementType枚举的元素)

Interface Type

Class  Interface  @interface  Enum  

l 注解的属性

String color()default "blue";//这是一个方法,返回一个字符串

//按照属性的用法来使用,默认值是blue

如果注解只有一个value属性要设置,就可以不写"value=",只写要赋的值

System.out.println(annotationDemo.color());

其他高级属性:

数组类型的属性:

int[] array()default {3,4,5};

用的时候:

@AnnotationDemo(array={1,2,3})

如果数组只有一个元素可以省略大括号

枚举类型的属性:

注解类型的属性:

@AnnotationDemo(给属性赋值:annotationDemo=@AnnotationDemo

("hello"))就是这个注解的实例对象



----------- android培训java培训、java学习型技术博客、期待与您交流! ------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值