ps:有时间好好整理下格式。从别的编辑器拷贝过来啥都没了。
~~~~~~~~~~~~~~·
2、java程序设计环境
JDK 开发java使用的软件;
JRE 运行java使用的软件;SE 用于桌面或简单服务器应用的java平台--废弃 EE 用于复杂服务器应用的java平台--通用。ME 手机或其他小型设备的java平台--废弃 库源文件和文档: src.zip---包含了所有公共类库的源代码。 JDK目录结构: bin 编译器和工具, demo演示, docs 类库文档,include 用于编译本地方法的文件,jre运行环境文件,lib 类库文件,src类库源文件。 命令行 javac程序是java的编译器,把java后缀的文件编译成.class文件,并发送到java虚拟机,虚拟机执行编译器放在class文件中的字节码。 注意大小写,编译时需要文件名,运行时需要类名。 appletviewer程序 ,jdk自带的快速测试applet,需要提供一个HTML文件名。可在浏览器中启用applet查看。3、java的基本程序设计结构
System.out.println("xxxx"); //out.print输出不换行。
大小写敏感,类名已大写字母开头,文件名必须与公共类的名字相同,用.java扩展。强调main也public。 /** 这种注释可以自动生成 *文档*/ //换行时加个* 明显标识 强类型语言,8种基本类型(4整型、2浮点、1Unicode编码的字符单元char,1boolean); 1整型 没有小数部分的数值,可负数, int 4字节 ,short 2字节,long 8字节 , byte 1字节; 与运行java代码的机器无关。长整型数值加后缀L,数字加下划线只为了让人更易读,编译器会去除。 2浮点类型 float4字节,double8字节 。float类型数值有后缀F(3.14F),没有默认是double(或加D)。 Double.NaN 不是数字? if(x == Double.NaN) //永远false, if(Double.isNaN(x)) //检查x 浮点型不适用于禁止出现舍入误差的金融计算。 System.out.println(2.0-1.1)将打印0.89999999。 使用BigDecimal类实现这类运算。 3char类型 单字符, 转义字符 \b退格,\t制表, \r换行=\u000a, \n回车=\u000d, Unicode 范围从\u0000-\uffff。 JDK5.0开始, 代码点(code point)与一个编码表中的某个字符对应的代码值;看不懂喽~P52~ 4boolean 类型,false和true,和整型值不能进行相互转换。 用final指示常量, final double PI=3.14; //名称全大写 用strictfp关键字指定方法必须使用严格的浮点计算来产生理想的结果。 位运算>>>用0填充高位,>>用符号位填充高位。 Math类注重性能,如果注重结果使用StrictMath类; 对浮点数进行舍入运算,得到最接近的整数 Math.round(x);--round默认返回long类型。 枚举: enum Size{ SMALL,MEDIUM,LARGE,EXTRA_LARGE}; Size s=Size.SMALL; 字符串 s.substring(0,3); String 类对象称为不可变字符串, s.equals(t) //是否相等。 不区分大小写用 equalsIgnoreCase; 空串是"",长度0的字符串, if(str.length()==0) //检查空串 if(str!=null) //检查是否null; char charAt(int index) boolean endsWith(String suffix); toLowerCase/toUpperCase, 小写/大写 构建字符串 StringBuilder类比拼接(+)高效; StringBuilder sb=new StringBuilder(); sb.append(chOrStr); sb.toString(); StringBuffer效率低点,但允许多线程执行 添加或删除字符; 所在包 java.lang.StringBuilder void setCharAt(int i, char c);将i位置设置为c; StringBuilder insert(int offset, StrOrChar s); StringBuilder delete(int startIndex, int endIndex); 输入输出 System.out.println ,输出 标准输入流 需要构造一个Scanner对象 // 所在包 import java.util.*; Scanner in=new Scanner(System.in); String name=in.nextLine();//读取一行 String aWord=in.next();//读取直到遇到空格; int age=in.nextInt(); boolean hasNext(); hasNextInt(); Scanner类是输入可见的,不适合密码; Console cons=System.console(); char[] passwd = cons.readPassword("Password:"); 包:java.io.Console System.out.printf("%,.2f",1000.0/3.0); //打印 3,333.33 可使用多个标志, +正负号,-左对齐,.分组分隔符,(负数加括号; 可使用String.format方法创建一个格式化的字符串但不打印; 时间日期 System.out.printf("%tc", new Date()); c 完整日期和时间, F :2004-02-09 ,D 02/09/2004, T 24小时时间18:05:19, 文件输入输出 读入文件Scanner in=new Scanner(Paths.get("myfile.txt")); //java.util.Scanner 写入文件PrintWriter out=new PrintWriter("myfile.txt");//如果文件不存在则创建;java.io包 out.println("you can !"); 写入后需调用out.flush(); 刷新流; 用户路径 String dir=System.getProperty("user.dir"); //java.nio.file.Paths 如果用不存在的文件构造一个Scanner,或不能被创建的文件名构造一个PrintWriter,会异常; 在方法中用throws子句标记, void sub() throws FileNotFoundException {}; 流程控制 while(condition)statement; do statement while(condition); for(int i=1; i<=10; i++){} switch(x){ case 1: break; ...} -不建议使用switch,可在编译时加 -Xlint:fallthrough选项,强制少break警告; -也可在外围方法加标注@SuppressWarnings("fallthrough");消除警告; 带标签的break和continue:标签是 name:, break/continue到标签后的语句块末尾,再检查是否正常退出语句块; 都不建议使用; 大数值 java.math 中的 BigInteger和 BigDecimal。可任意长度; BigInteger a = BigInteger.valueOf(100); a.add(b);//不能用 + - * / int compareTo(BitInteger other);//0相等,正数是大于,负数是小于; 数组 int[] a=new int[100]; System.out.println(Arrays.toString(a));//输出"[a1,a2.....]" 数组不能改变大小, 数组列表(array list)才可以。 for(variable: collection)statement; //实现了Iterable接口的类对象也可以。 初始化 int[] a={2,3,4}; //不需要new int[] a=new int[]{2,3,4}; 数组拷贝 int[] a= Arrays.copyOf(b, x * b.length); //通常用来增加数组的大小; 排序 Arrays.sort(a);//优化的快速排序算法; Math.random() 返回0到1(包括0,但不包括1)的随机浮点数; 抽取算法:用数组最后的元素值改写抽取值,然后数组可用长度减一; numbers[r] = numbers[n - 1]; n--; static int binarySearch(type[] a, type v);//二分搜索算法查找值v static void fill(type[] a, type v); //数组所有填充值v; 多维数组 int[][] x; System.out.println(Arrays.deepToString(x));//输出"[[3,2...],[a1,a2.....]...]"4 对象与类
三主要特性: 行为、状态、标识;
类之间的关系 依赖(uses-a)、聚合(has-a)、继承(is-a); 对象与对象变量的区别; 一个对象变量并没有实际包含一个对象,仅仅引用; 日历类 GregorianCalender类, 表示时间点的Date类:时间是用距离一个固定时间点(纪元 1970-01-01 00:00:00)的毫秒数标识的, GregorianCalender thisTime=new GregorianCalender(); //月份从0开始计数。 int month = thisTime.get(Calendar.MONTH); //通过常量和访问器来获取年月日等, thisTime.set(属性,value);thisTime.add(属性,vlaue); Date time=thisTime.getTime();//setTime(time); 转换。 int firstDayOfWeek = d.getFirstDayOfWeek();//一个星期中的第一天; java.text.DateFormatSymbols 下面有几个格式输出方法 String[] getShortWeekdays()/ getShortMonths(); 自定义类 在一个源文件中,只能有一个公有类; 警告: 不要编写返回引用可变对象的访问其方法;这个引用可能在外面被改写,破坏了类的封装。 代替用 对象的clone(); 静态域与静态方法 static修饰的变量,所有实例共享一个静态域; 可用于标识实例; private static int nextId=1; private int id; void setId(){ id=nextId; nextId++;} System有setOut方法,是本地方法,可设置不同的流,不是用java实现的。不推荐。 可使用对象名调用静态方法但不推荐; 工厂方法: 静态方法的常见用途,构造不同对象; 每一个类可以有个main,用作单元测试。 方法参数:java总是按值传递,没有引用调用!对象引用进行的也是值拷贝传递; 对象构造 重载,多个构造器(通过不同的方法签名-方法名和参数 实现); 默认域初始化,没有显式的构造器。不推荐,影响代码可读性; 无参构造器,常用; 参数名 public Employee(String aName, int aAge){name=aName;}//用a前缀; public Employee(String name, int age){this.name=name;}//用this访问当前对象 用this在构造器中调用另一个构造器,重用代码; public Employee(int age){ this("NewName",age);} 初始化块 一个类的声明中,可以包含多个代码块, {xxxx; xxx; xxxxxxx;} 三种初始化数据域的方法:构造器中赋值,声明时赋值,初始化块中赋值。 初始化块先于构造器执行; static 修饰的块只执行一次,其他的每次类实例化都执行; 调用构造器的具体步骤 a、所有数据域被初始化为默认值(0/false/null); b、按声明中出现的次序,依次执行初始化语句和初始化块; c、如构造器1调用了构造器2,则先执行2,再执行1。 对象析构与 finalize方法 Java不支持析构器;但当使用了文件或另一系统资源的句柄,使用finalize方法,它在垃圾回收器清除对象之前调用。实际中,不要依赖于该方法回收任何短缺的资源——不知道何时才回收。 使用关闭勾:Runtime.addShutdownHook,可确保在Java关闭前调用finalize方法; 包package 确保类名的唯一性;嵌套的包之间没有任何关系! 调用其他包的类,可在类名之前加包名,或 用import语句; 静态导入 用import可导入静态方法和静态域; import static java.lang.System.*; //可使用System的静态方法和静态域; out.println("xxxx"); exit(0); 包作用域 不显示声明private的类、方法、变量,可被同一包的所有方法访问;破坏封装。 类路径 类路径必须与包名匹配; JAR(Java归档)文件,可以用压缩文件工具打开查看JAVA文件; 共享类需要: P156的4.8类路径,暂时不懂。 文档注释 工具javadoc,由源文件生成一个HTML文档; 以专用的定界符/**开始的注释, 和代码同步; javadoc的程序utility抽取信息(包、公有类和接口等),信息是自由格式文本,标记有@开始, 文本第一句是概要性句子; 方法注释 @param 标量描述, @return描述,@throws类描述,表示有可能抛出异常。 @author 姓名 --类注释,作者 @version 文本 --版本条目 @since 文本 始于条目,引入特性的版本 @see 引用 超级链接,可选三种 @see package.class#feature label @see <a href="www.baidu.com">label</a> @see "text" 包注释 需在每一个包目录中添加一个单独的文件, 以package.html命名的文件,或package-info.java命名的java文件。P162. 注释抽取 javadoc -d docDirectory nameOfPackage 类设计技巧 保证数据私有(不破坏封装);对数据初始化;不在类中使用过多基本类型;缩减set或get访问器;分解过多的职责到其他类;类名和方法名提现职责; java不对局部变量初始化,但对对象的实例域初始化。 比如用Address类代替 String street/city/state等。5 继承
5.1类、超类、子类
继承是 is-A 关系,关键字extends ,(父类、超类、基类),子类; 置换法则:出现基类对象的地方都可以用子类置换。 //能置换,所以方法不能降低可见性; 调用基类方法:super.xxx(); //this是对象引用,super只指示编译器调用超类方法。 类似super();//调用超类对应构造器;放在自身构造器的第一条语句; 覆盖 override, 多态:一个对象变量可指示多种实际类型的现象,运行时自动选择调用哪个方法,称为动态绑定。 --申明为基类的引用,实际可引用基类实例,也可引用子类实例,虚拟机根据实际的引用来调用相关(公有的,非子类特有新增的)方法。 申明为基类的引用,肯定不能调用子类的方法。 subA[] aList=new subA[3]; baseA[] sList=aList; //这时aList和sList将指向同一对象; aList.subDo(); //ok sList.subDo();//ERROR!虽然指向同一个对象。方法是private /static/ final 的或构造器,调用它们是静态绑定。
虚拟机为每个类创建了一个方法表,调用时直接查表; 阻止继承: final类和方法 类的特定方法可被声明为final,这样子类不能覆盖它;final类的所有方法自动的称为final方法。 有些认为:不使用多态的都声明为final。 早期java中,避免动态绑定带来系统开销而使用final关键字。 一个方法没有被覆盖且很短,编译器优化(内联 inlining),e.getName()被转换为e.name域,提升效率; 强制类型转换 当一个基类声明中引用的确实是子类的对象实例时,可以强制类型转换为子类,或者说,用一个子类的声明去指向这个基类所引用的对象实例; BaseA aBaseA=new SubA(); SubA a = (SubA)aBaseA; //暂时忽视申明类型,使用对象的全部功能。 可用 instanceof 关键字 测试 if(a instanceof SubA){dosomething;} 抽象类 : abstract修饰,且包含一个或多个抽象方法的类本身必须被声明为抽象。 抽象类还可以包含具体数据和具体方法。 抽象类不能被实例化,但可以有构造器,在子类的构造器中 用super()调用它; 使用通配符 编译多文件 :javac *.java; 或javac -d . A.java B.java ,生成到下一级目录。 受保护访问:protected,仅子类可访问;--修改可能影响子类,违背OOP的封装原则;--对同包其他类都可见。 控制可见性 1、仅本类-private; 2 对所有类-public; 3、对本包和所有子类可见-protected; 4、对本包--默认,不需修饰符。 5.2 Object:所有类的超类 Object obj=new Employee("name",age);//Object类型的变量可引用任何类型的对象。 只有基本类型不是对象;数组类型(哪怕基本类型的数组)都扩展于Object类。 equals 对于对象是判断俩对象是否具有相同的引用。 通常对类来说是无意义的,所以每个类要实现自己的equals。 编写一个完美equals的建议: 0、参数命名otherObject, 显式转换后为other;类型是Object,这样才能完全覆盖超类。 1、判断引用是否相同 this==otherObject; return true; 2、判断是否null otherObject==null return false; 3、判断类型一致 getClass()!=otherObject.getClass() //false 4、将otherObject强制转换为当前类的对象,判断状态。 Employee other= (Employee)otherObject; Objects.equals(other.name,this.name); static Objects.equals(a,b);若a,b都为null,则true,若一个null,返回false; static Objects.equals(type[] a,type[] b); 数组长度相同,且对应位置元素也相同,则true; 子类中定义equals方法时,要先调用超类的equals。 相等测试与继承 instanceof 判断可能是继承关系,所以不适合这种判断。 如果equals的语义在子类中有所改变,则用getClass, 如果没改变,用instanceof,且将超类的eauals声明为final 。 equals 对任何非空引用,满足 自反性,对称性,传递性,一致性。对于空引用,返回false; hashCode方法 散列码 是由对象导出的一个整型值。Object类的对象默认为其存储地址。 如果重定义equals,必须重新定义hashCode,以便用户将对象插入得到散列表中。 一般: Objects.hash(p1,p2,p3);//组合类的多个属性,生成散列码。 (java.lang.Object 1.0包) int hashCode() 返回散列码,相等的对象要求返回相等的散列码。 int Objects.hash(o1,o2,o3....) 由提供的所有对象的散列码组合得到新的散列码 int Objects.hashCode(Object a) 如果a为null则返回0,否则返回a.hashCode()。 (java.util.Arrays 包) static int hashCode(type[] a) 数组的散列码 toString方法 对象的toString可自定义。建议 类名加方括号的域值,如 java.awt.Point[x=20,y=30] ; 类名用 a.getClass().getName();获取; 技巧:在需要调用x.toString()的地方,用""+x替代。 这样x是基本类型时也能够执行。 只要对象与字符串通过"+"连接 ,Java编译就自动调用toString方法。 也可以用System.out.println(x);//是对象时默认x.toString(); Object的toString,是输出对象的所属类名和散列码。 数组用Arrays.toString(a); 多维用Arrays.deepToString(b); 调试信息: System.out.println("Current ObjectX =" + obj); //需要对象实现自己的toString(); 强烈建议为自定义的每一个类增加toString()方法; java.lang.Object包 Class getClass() 返回包含对象信息的类对象; java.lang.Class 包 Class getSuperclass()返回类的超类信息; 5.3泛型数组列表 Java允许在运行时确定数组大小,int size=100; Employee[] staff=new Employee[size]; 泛型里面的类型参数必须是 Object 的子类。 ArrayList是采用 类型参数的泛型类, <Employee>指定类型, ArrayList<Employee> staff=new ArrayList<>(); //Vector类是老版本的动态数组, 老版本中的ArrayList类元素是Object,没有泛型。 数组列表管理着内部数组的引用,若数组已满,则自动创建更大的数组并copy元素到新数组中。 如已清楚或能估算穿数组元素数量,可调用ensureCapacity方法,分配一个包含指定数量元素的内部数组。 也可以 ArrayList<Employee> staff=new ArrayList<>(100); //指定数量 .size()返回实际元素数目。 .add(x)添加元素, .add(index,x); .remove(n); .trimToSize()确认元素不会再增删后,将数组列表的存储容量消减到当前尺寸,剩下的空间以便垃圾回收器回收。 new ArrayList<T>(); 构造空数组列表; new ArrayList<T>(initialCapacity);用指定容量构造一个空数组列表。 staff.set(i,harry); //set和get 访问元素,注意实际的size; 5.4对象包装器与自动装箱 需要将基本类型转换为对象时用到。int-Integer,包装器(wrapper)是final的。 对象包装器是不可变的!不允许更改便装在其中的值。 如:ArrayList<int> aInt=new ArrayList<int>(); 报错: Syntax error, insert "Dimensions" to complete ReferenceType。 泛型数组列表里面的类型参数必须是 Object 的子类,因此不能使用 int,而应该使用 int 的包装器类型 Integer。 ArrayList<Integer> aInt=new ArrayList<Integer>(); list.add(3) 自动转换为 list.add(Integer.valueOf(3)); ---自动装箱(autoboxing)。 int n=list.get(i); 自动转为list.get(i).intValue():自动拆箱; 类似:Integer n=3; n++; ---- 先拆箱,再自增,再装箱。 包装器对象比较,调用equals(); 装箱和拆箱是编译器的工作,是语法糖。虚拟机执行的是编译器编译的字节码。 包装器还可以包含一些数值/字符串 转换方法。 int x=Integer.parseInt(s); System.out.println(Integer.toString(System.out.hashCode(),16)); toString(int i, int radix) //返回数值i的给定参数进制的表示; intValue() 返回包装器的值。 int x=Integer.parseInt(s,int radix);//radix是说明字符串s的进制表现形式。 5.5参数数量可变的方法 Java SE5.0以后提供的, 如printf,一个格式化字符串,一个Object[] public static double max(double...values){ for(double v : values) if(x)doSomething();} //...是无限参数 5.6枚举类 public enum Size{SMALL,MEDIUM,LARGE,EXTRA_LARGE}; 是有4个实例的类; Enum类的子类是Size。 比较俩枚举值时不需要调用equals,直接==; x.toString()将返回字符串; Enum Enum.valueOf(Size.class,"SMALL")是逆方法, Size.values()返回包含全部枚举值的数组; ordinal()返回枚举的位置,从0开始基数。 int compareTo(E other) 在前为负值,this==other则0,在后则正值。 5.7反射 反射库(reflection library),JavaBeans中大量使用。 能够分析类能力的程序称为反射(reflective)。 运行中分析类的能力;运行中查看对象;---使用它的主要是工具构造者。 1、Class类) 程序运行期间,Java运行时系统为所有对象维护一个被称为运行时的类型标识。 记录着对象所属的类。 Object类的getClass()返回一个Class类型的实例; Class.forName(className);返回类名对应的Class对象; 也可以用T.class来获取类对象; 一个Class对象实际上表示一个类型,但未必一定是类,如int.class。 可以用==比较类对象; x.getClass().newInstance();快速创建一个类的实例;(需要一个无参的构造器) forName和newInstance配合使用,可由字符串中的类名创建一个对象。 String s="java.util.Date"; Object m=Class.forName(s).newInstance(); 2、捕获异常) 异常类型: 未检查异常和已检查异常。 try{ dosomethings();}catch(Exception e){} Throwable类(Exception的超类)的printStackTrace()打印出栈的轨迹; 3利用反射分析类的能力)--暂忽略 java.lang.reflect包中Field/Method/Constructior分别描述类的域、方法、构造器。 还有Modifier类的静态方法; 4运行时使用反射,5使用反射编写泛型数组代码、6调用任意方法)暂忽略 5.8继承设计的技巧 1公共操作和域放在超类; 2不使用受保护的域; (子类无限制,谁都可以写个派生类并访问protected实例域,破坏封装) (java中,同一个包中的所有类都可以访问proteced域。) 3使用继承实现 is-a关系;(钟点工不是特殊的雇员,不是is-a关系,不能继承) 4除非所有继承的方法都有意义,否则也不要使用继承。 5覆盖方法不产生非预期行为;-覆盖基类的方法时,不偏离最初的设计想法。 6使用多态,而非类型信息; 7不过多使用反射;6 接口和内部类
接口interface-对象克隆-内部类inner class-代理proxy
6.1接口 对类的一组需求描述,类要遵从接口描述。 接口中所有方法自动属于public。所有域是public static final。 更重要的是知道接口不能提供哪些功能。 接口可以定义常量,但不能含有实例域,也不能有方法实现。 implements关键字。 java.lang.Comparable<T>的int compareTo(T other); 小于则负值,相等0,大于正值。 强制的是 “实现接口”,而不是实现方法。----------一定注意。 java.util.Arrays包的 static void sort(Object[] a) 对数组a的元素排序,要求元素必须属于实现了Comparable接口的类。 如果父子类对象比较的含义不一样,那属于不同对象的非法比较。或者比较定义在超类且final。1接口特性)不是类,不能new实例化。但能声明变量,变量引用实现了接口的类对象。
使用instance检查一个对象是否实现了某个特定接口 if(anObject instanceof XInterface){} 接口可以继承接口 interface X extnds xBase; 接口可以只定义常量,但有点偏离初衷,建议NO。 6.2对象克隆 Object类的clone方法默认是浅拷贝。 对于每一个类,进行如下判断: 1默认的clone是否满足,2默认的clone是否能通过调用子对象的clone得到修补,3是否不应该使用clone。 对于不满足1和2的, 实现Cloneable接口,使用public重新定义clone。 Cloneable接口的出现和接口的正常使用没有任何关系。clone方法是从Object类集成而来。 接口只作为标记,表明类设计者知道要进行克隆处理。 ------标记接口tagging interface或者marker interface。用途是可以使用instanceof进行检查。 即便默认实现(浅拷贝)满足,也该实现Cloneable接口,且定义public并调用super.clone(); public X clone throws CloneNotSupportedException { return (x)super.clone();} 所有数组类型均包含clone方法,且为public,可以创建一个新数组。 int[] cloned= luckyNumbers.clone(); 6.3接口与回调 callback 回调,指出某特定事件发生时采取的动作。 Java标准类库传递一个对象给定时器,定时器调用其方法;要求对象所属类实现了java.awt.event包的ActionListener接口。里面一个方法void actionPerformed(ActionEvent event); 定时器调用actionPerformed方法。 一个例子-明天运行一下。且整理笔记。 6.4内部类 已读,笔记待整理。