【黑马程序员】 java笔记——基础加强
来源:互联网 发布:淘宝一元包邮 编辑:程序博客网 时间:2024/05/21 02:35
Java基础加强学习
1. 了解IDE
IDE其实就是集成开发环境。
2. 静态导入
import语句可以导入一个类或者某个包中的所有类。
import Static语句导入一个类中的某个静态方法或者所有的静态方法。
//直接导入方法
Import staticjava.lang.Math.max;
//静态类下的方法都导入
Import staticjava.lang.Math.*;
3. 可变参数
主要涉及到的是方法覆盖和方法重载。
一个方法接收的参数个数不固定,例如:
System.out.println(add(2,3,4));
System.out.println(add(2,3,4,5));
Override和overload的区别:
Overload是重载,同一个函数可以有不同的参数列表。
Override是覆写父类的方法。
可变参数的特点:
只能出现在参数列表的最后;
…位于变量类型和变量名之间,前后空格可选;
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
示例:
class VariableArgs{ public static int add(int x, int ... args) { //把args当作int数组就可以了 int sum = x; for(int a:args) { sum += a; } return sum; } public static void main(String[] args) { System.out.println(add(1,2,3,4,5,6)); }}
4. 增强for循环
增强for循环的语法格式:
for(type 变量名:集合变量名)
{}
注意事项:
1.迭代变量必须在{}中定义。
2.集合变量可以是数组或实现了Iterable接口的集合类。
举例:
public Static int add(int x,int…… args){ int sum=x; for(int arg:args)//此处就是增强for循环的格式 { sum+=sum; } return sum;}
5. 基本数据类型和自动装箱与自动拆箱
自动装箱
Integer num1=12;
自动拆箱:
system.out.println(num1+12);
基本数据类型的对象缓存:
Inter num1=12; Inter num2=12; System.out.println(num1=num2); Integer i1 = 5;Integer i2 = 5;System.out.println(i1==i2); //trueInteger i3 = 128;Integer i4 = 128;System.out.println(i3 == i4); //false
Java将小于一个字节的数字(-128~127)放在内存中常驻。而对于大于一个字节的才在堆中创建。(python中也用到此技术)
享元模式(flyweight)
多个小的对象,内容/属性大部分相同。可以将其统一设计为一个对象,相同的部分作为内部状态,不相同作为外部状态内容。其他不同的部分通过参数传入来设置。
Integer.valueOf(int) //将int显式得转为Integer
Integer.valueOf(5) == Integer.valueOf(5) //true
6. 享元模式:flyweight pattern
简而言之就是共享物件,用来尽可能减少内存的使用量。
7.枚举
什么是枚举?
枚举是一种特殊的类。
枚举一般是结合内部类出现的。同时枚举一般是用来表示那些确定的元素。比如星期几,性别等。枚举的对象是确定的,类或者方法调用不能创建新的,只能调用枚举类中已经存在的。
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错;枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。
用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能
私有的构造方法:
每个元素分别用一个公有的静态成员变量表示
可以由若干个公有方法或抽象方法,例如:要提供nextDay方法必须是抽象的
采用抽象方法定义nextDay将大量的if else语句转移成了一个个独立的类(使用内部类)
枚举的基本应用:
举例:定义一个WeekDay的枚举
扩展:枚举类得values.valueOf.name.toString.final等方法
总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象。例如可以调用WeekDay.SUN.getClass.getName和WeekDay.getClass.getName
枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和抽象方法
枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
带构造方法的枚举
构造方法必须定义成私有的
如果有多个构造方法,该如何选择哪个构造方法?
看元素初始化了MON()和MON(1)调用不同的构造方法
枚举元素MON和MON()的效果一样,都是调用默认的构造方法
带方法的枚举
定义枚举trafficLamp
实现普通的next方法
实现抽象的next方法:每个元素分别是由枚举类得子类来生成的实例对象,这些子类采用类似内部类的方式进行定义
增加上表示时间的构造方法
枚举只有一个成员时,就可以成为一种单例的实现方式。
name() //得到枚举值的名称
ordinal() //得到枚举值在枚举声明中的位置
static EnumClass valueOf(String name); //得到枚举名称为name的枚举值
static int[] values(); //获得枚举对应的所有值组成的数组。
枚举类型在switch中不需要枚举名,只需要枚举值:
Weekday w = Weekday.MON;switch(w){ case(MON): … Break;……}
带有构造器的枚举
public enum WeekDay{/* 元素相等于静态的成员,没有括号的时候调用默认构造方法,也可以指定调用其他构造函数。*/ SUN(0),MON(1),TUE(2),WED(3),THI(4),FRI(5),SAT(6); //元素列表必须在枚举类最前面。 //构造函数必须是私有的。 private WeekDay(int day) {}}
带有抽象方法的枚举
内部类有四种访问权限,而普通的类只有public和包访问权限。
public class Weekday1{ public static void main(String args[]){ //调用父类有参数的构造方法: new Date(300){}; } public enum TrafficLamp{ RED(30){ public TrafficLamp nextLamp(){ return GREEN; } }, GREEN(45){ public TrafficLamp nextLamp(){ return YELLOW; } }, YELLOW(5){ public TrafficLamp nextLamp(){ return RED; } }; public abstract TrafficLamp nextLamp(); private int time; private TrafficLamp(int time){ this.time = time;} }}
上面中的枚举类型中会编译出三个class文件。
如果枚举只有一个成员时,可以作为一种单例模式的实现方式。
7. 反射
反射的基石:Class类
Class-à代表Java中各个java类,描述java类的相关属性:类名/父类/所在包等等
Class类对象包含其他类的字节码信息。每个类对应一个字节码文件。
Date.class //得到Date类字节码
对象.getClass(); //得到对象所属类的字节码
Class.forName(“java.lang.String”); //得到指定类的字节码
其工作情况分两种:已载入内存的字节码和未载入内存的字节码
前者可以直接获得内存中的字节码,后者则会调用类加载器加载类,再获得其类字节码。
上面就是三种获得类字节码的方法,只要是同一个类,那么得到的最终是同一个字节码。
其中反射的话通常是用Class.forName方式,因为运行时不知道类名。
Class.forName还会抛出ClassNotFoundException.
9个预定义的Class对象(一开始就载入虚拟机):8个基本数据类型和void
示例:
publicclass ReflectTest{ public static void main(String[] args)throws Exception { String str = "123"; Class cls1 = str.getClass(); Class cls2 = String.class; Class cls3 = Class.forName("java.lang.String"); System.out.println( cls1 ==cls2); System.out.println( cls1 ==cls3); System.out.println(cls1.isPrimitive()); System.out.println(int.class.isPrimitive()); //false System.out.println(int.class== Integer.class); //true:Integer:public static finalClass<Integer> TYPESystem.out.println(int.class== Integer.TYPE); //falseSystem.out.println(int[].class.isPrimitive());//trueSystem.out.println(int[].class.isArray()); }}
什么是反射?
反射就是把java类中的各种成分映射成相应的java类。
如何得到各个字节码对应的实例对象(class类型)
1.类名.class,例如:System.class;
2.对象.getclass(),例如:newDate().getclass();
3.class.forName(“类名”),例如:class.forName("java.util.Date");
Constructor类
1.得到某一个类所有的构造方法:
例子:Constructor[]constructor=Class.forName(“java.lang.string”).getConstructor
2.得到某一个构造方法:
例子:Constructorconstructor=
Class.forName(“java.lang.String”).getConstructors(StringBuffer.class)
获得方法时要用到类型
3.创建实例对象:
一般方式:Stringstr=new String(new StringBuffer(“abc”));
反射方式:Stringstr=(String)Constructor.newInstance(new String Buffer("ABC");
调用获得的方法时要用到上面相同类型的实例对象。
Class.newInstance()方法:
例子:String obj = class.forName(“java.lang.String”)newInstance();
该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
该方法内部的具体代码是怎么写的?用到了缓存机制来保存默认构造方法的实例对象。
Field类反射
Field类代表某个类中的一个成员变量
需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”。
字节码的比较,使用 = =,不要使用equals;(因为这里只是一份字节码,没有第二份,所以不用equals)
代码:
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(cls1==cls3); System.out.println(cls1.isPrimitive()); System.out.println(int.class.isPrimitive()); System.out.println(int.class==Integer.class); System.out.println(int.class==Integer.TYPE); System.out.println(int[].class.isPrimitive()); System.out.println(int[].class.isArray()); //记住1.强转 2.参数类型必须一致 //Constructor类反射 Constructor constructor = String.class.getConstructor(StringBuffer.class); String str2 = (String)constructor.newInstance(newStringBuffer("abcd")); System.out.println(str2.charAt(3)); //Field类反射 //field不是对象身上的变量,而是类上的,要用它去取某个对象身上的值 ReflectPoint pt1 = new ReflectPoint(3,5); Field fieldy = pt1.getClass().getField("y"); System.out.println(fieldy.get(pt1)); Field fieldx = pt1.getClass().getDeclaredField("x"); fieldx.setAccessible(true);//暴力反射 System.out.println(fieldx.get(pt1)); changeStringValue(pt1); System.out.println(pt1); //str1.charAt(1); Method methodCharAt = String.class.getMethod("charAt",int.class); System.out.println(methodCharAt.invoke(str1, 1)); } private static void changeStringValue(Objectobj) throws IllegalArgumentException, IllegalAccessException { Field[] fields = obj.getClass().getFields(); for(Field field : fields) { if(field.getType()==String.class) { String oldValue = (String)field.get(obj); String newValue = oldValue.replace('b', 'a'); field.set(obj, newValue); } } }
8.Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子:MethodcharAt=class.forName(“java.lang.String”)
getMethod("charAt",int class);
调用方法
一般方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str,1);
如果传递给Method对象的invoke()方法的一个参数为null,说明该Method对象对应的是一个静态方法。
JDK1.4没有可变参数,因此invoke中使用Object数组作为参数。
JDK1.5向下兼容
示例:
import java.lang.reflect.*;class TestArgs{ public static void main(String[] args) { for(String str: args) { System.out.println(str); } }}public class ReflectTest{ public static void main(String[] args) throws Exception { //TestArgs.main(newString[]{"111","222"}); //String startClassName =args[0]; Method mainMethod =Class.forName(args[0]).getMethod("main",String[].class); //编译报错,mainMethod.invoke(null, newString[]{"111","222","333"}); //一个Object数组,只有一个元素,这个元素是一个String[]数组 mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}}); //跟编译器打招呼:我这个String[]组你就当作一个Object得了。 mainMethod.invoke(null,(Object)new String[]{"111","222","333"}); }}
当使用mainMethod.invoke(null, newString[]{"111","222","333"});时,java编译器编译报错,原因是JDK1.4中有invoke(Object[])的方法。为了向下兼容,JDK1.5将newString[]{"111","222","333"}作为一个Object数组来处理,即分拆为三个参数传给函数。
警告: 最后一个参数使用了不准确的变量类型的 varargs 方法的非 varargs 调用; mainMethod.invoke(null, new String[]{"111","222","333"});
对于 varargs 调用, 应使用多个Object分开,对于非 varargs 调用, 应使用 Object[], 这样也可以抑制此警告。
为此可以使用下面两个方法:
mainMethod.invoke(null, newObject[]{new String[]{"111","222","333"}});
mainMethod.invoke(null,(Object)new String[]{"111","222","333"});
9.数组的反射:
具有相同维数和元素类型的数组属于同一类型,即具有相同的class实例对象。
代表数组的class实例对象的getSuperClass()方法返回的父类为Object类对应的class。
示例:
public class ReflectTest { public static void main(String[] args) { int[] a1 = new int[3]; int[] a2 = new int[4]; int[][] a3 = new int[3][4]; String[] a4 = new String[4]; /* System.out.println(a1.getClass()== a2.getClass()); System.out.println(a1.getClass()== a3.getClass()); System.out.println(a1.getClass()== a3.getClass()); */ //维数相同 //System.out.println(a1.getClass()== a2.getClass()); //维数不同连编译都报错了 //System.out.println(a1.getClass()== a3.getClass()); //输出为[[I System.out.println(a3.getClass()); //compile error System.out.println(a1.getClass() == a4.getClass()); }}
补充知识点:int不是一个Object,但是int[]是一个Object。
int[] a1 = new int[3]; int[] a2 = new int[4]; int[][] a3 = new int[3][4]; String[] a4 = new String[4]; System.out.println(a1.getClass().getSuperclass().getName()); System.out.println(a4.getClass().getSuperclass().getName()); Object aObj1 = a1; //a1是int数组,里面每个元素是int,不是objcet,不能够Object[]aObj2 = a1; Object aObj3 = a3; //a3是二维数组,里面每个成员是一维int数组。一维int数组是Object Object[] aObj4 = a3; //都是打印出 类名@hashCode System.out.println(a1); System.out.println(a3); System.out.println(a4); //使用asList打印。JDK1.4使用Object数组 //由于a1是int数组。它不能当作一个Object数组,只能将其当作一个Object //所以打印Arrays.asList(a1)还是得到一个只有一个元素的List。//Arrays.asList接受可变参数,同时还有1.4以前的接受数组的asList System.out.println(Arrays.asList(a1)); //a3转为一个List,每个元素是一位数组。 System.out.println(Arrays.asList(a3)); //字符数组则按预想结果处理 System.out.println(Arrays.asList(a4));
打印结果:
java.lang.Object
java.lang.Object
[I@1a06f956
[[I@3fdb8a73
[Ljava.lang.String;@665ea4c5
[[I@1a06f956]
[[I@45edcd24, [I@7f371a59, [I@7aa30a4e]
[null, null, null, null]
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,即可以当作Object类型使用,不可以当作数组型使用。
利用反射打印数组示例:
public static void printObject(Object obj) { Class cls = obj.getClass(); if(cls.isArray()) { int len = Array.getLength(obj); for(int i = 0; i< len; ++i) { printObject(Array.get(obj,i)); } } else { System.out.println(obj); } }
Arrays.aslist()方法处理int[]和String[]的差异:
Array工具类用于完成对数组的反射操作。
HashSet类:就是采用哈希算法存取对象集合。
HashSet中不能包含相同对象的两个引用,但是可能包含包含两个哈希值相同的对象。
总结:HashSet在存储对象引用时,先计算hashCode(可以在复写的hashCode方法中输出来看看是不是),然后在内存中看看是否已经存在引用。如果不存在直接存入集合,否则比较这些hash值相同的对象,如果新对象和已有对象都不equals,才存入新对象。
反射的作用:实现框架功能
框架调用自己编写的类。
框架不知道将会调用什么样的类,不能够new对象。
下面的方法通过读取配置文件className来决定运行时使用什么样的集合类型。
className文件中内容是:
className=java.util.ArrayList
public class RefelctTest2 { public static void main(String[] args) throws Exception { InputStream is = newFileInputStream("className"); Properties perp = newProperties(); perp.load(is); is.close(); String className =perp.getProperty("className"); //Collection coll = newArrayList(); Collection coll =(Collection)Class.forName(className).newInstance(); ReflectPoint rpt1 = newReflectPoint(3,4); ReflectPoint rpt2 = newReflectPoint(3,4); ReflectPoint rpt3 = newReflectPoint(9,9); coll.add(rpt1); coll.add(rpt2); coll.add(rpt3); coll.add(rpt3); //根据配置文件中内容不同而不同:ArrayList是4,HashSet是2 System.out.println(coll.size()); }}
- 黑马程序员——张孝祥Java基础加强笔记
- 【黑马程序员】 java笔记——基础加强
- 黑马程序员——java基础加强
- 黑马程序员——java基础加强
- 黑马程序员—java之基础加强
- 黑马程序员—Java基础加强(枚举)
- 黑马程序员—Java基础加强(反射)
- 黑马程序员—Java基础加强(JavaBean)
- 黑马程序员 Java基础加强笔记
- 黑马程序员笔记:Java基础加强之一
- 黑马程序员 — 基础加强
- 黑马程序员——Java基础---基础加强
- 黑马程序员—Java基础加强学习笔记之泛型
- 黑马程序员—Java基础加强学习笔记之枚举&反射
- 黑马程序员——Java基础加强—高新技术
- 黑马程序员——java基础加强(一)
- 黑马程序员—Java基础加强—(泛型)
- 黑马程序员—Java基础加强—(枚举)
- 非归档模式下也可能能够recover?
- Linux系统守护进程xinetd与独立守护进程standalone
- 黑马程序员——面向对象程序设计
- 关于Layout_weight的布局问题
- 十一周——回文数
- 【黑马程序员】 java笔记——基础加强
- Linux Oracle 启动过程(个人)
- matlab2013a 中 mex代码的升级问题
- 十一周——回文数(bool版)
- sdk manager制作avd,cpu/abi对应的是灰色的
- android init.rc 语法分析
- 函数指针的简单应用2
- Java Socket 基础
- Hdu 4772 Zhuge Liang's Password