Java的核心技术啥?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java的核心技术啥?相关的知识,希望对你有一定的参考价值。
今年30了,想学门技术改行做互联网,不知道核心技术都是啥,还能不能学会
第一:Java虚拟机 Java虚拟机的主要任务是装在class文件并且执行其中的字节码。Java虚拟机包含一个类装载器,它可以从程序和API中装载class文件。Java API中只有程序执行时需要的那些类才会被装载。字节码由执行引擎来执行。不同的Java虚拟机中,执行引擎可能实现得非常不同。在由软件实现的虚拟机中,最简单的执行引擎就是一次性解释字节码。另一种执行引擎更快,但是也更消耗内存,叫做"即时编译器(just-in-time compiler)"。在这种情况下,第一次被执行的字节码会被编译成本地机器代码。编译出的本地机器代码会被缓存,当方法以后被调用的时候可以重用。第三种执行引擎是自适应优化器。在这种方法里,虚拟机开始的时候解释字节码,但是会监视运行中程序的活动,并且记录下使用最频繁的代码段。程序运行的时候,虚拟机只把那些活动最频繁的代码编译成本地代码,其他的代码由于使用得不是很频繁,继续保留为字节码-由虚拟机继续解释它们。一个自适应的优化器可以使得Java虚拟机在80%~90%的时间里执行被优化过的本地代码,而只需要编译10%~20%的对性能有影响的代码。 当Java虚拟机是由主机操作系统上的软件实现的时候,Java程序通过调用本地方法(native method)和主机交互。Java中有两种方法: Java方法和本地方法。Java方法是由Java语言编写,编译成字节码文件,存储在class文件中的。本地方法是由其他语言(比如c,c++或汇编语言)编写的,编译成何处理器相关的机器代码。本地方法保存在动态链接库中,格式是各个平台专有的。运行中Java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库,并调用这个方法。本地方法是联系Java程序和底层主机操作系统的连接方法。第二:类装载器的体系结构 一个Java应用程序可以使用两种类装载器:"启动(bootstrap)"类装载器和用户定义的类装载器。启动类装载器(这是系统中唯一的)是Java虚拟机实现的一部分。启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括Java API类(启动类装载器也被称为原始类装载器、系统类装载器或者默认类装载器)。 Java应用程序能够在运行时安装用户定义的类装载器,这种类装载器能够使用自定义的方式来装载类。例如,从网络下载class文件。尽管启动类装载器是虚拟机实现的本质部分,而用户定义的类装载器不是,但用户定义的类装载器能够用Java来编写,能够被编译成class文件,能够被虚拟机装载,还能够像其它对象一样实例化。 由于有用户定义类装载器,所以不必再编译的时候就知道运行中的Java应用程序中最终会加入的所有的类。用户定义的类装载器使得在运行扩展Java应用程序成为可能。当它运行时,应用程序能够解决它需要哪些额外的类,能够决定是使用一个或是更多的用户定义的类装载器来装载。由于类装载器是用Java编写的,所以用任何在Java代码中可以表述的风格来进行类装载。这些类可以通过网络下载,可以从某些数据库中获取,甚至可以动态生成。 每一个类被装载的时候,Java虚拟机都监视这个类,看到它到底是被启动类装载器还是被用户定义类装载器装载。当被装载的类引用了另外一个类时,虚拟机就会使用装载第一个类的类装载器装载引用的类。例如,如果虚拟机使用一个特定的类装载器装载Volcano这个类,它就会使用这个类装载器装载Volcano类使用的所有类。 由于Java虚拟机采取这种方式进行类的装载,所以被装载的类默认情况下只能看到被同一个类装载器装载的别的类。通过这种方法,Java的体系结构允许在一个Java应用程序中建立多个命名空间。运行时的Java程序中的每一个类装载器都有自己的命名空间。 Java应用程序可以创建多少个(或多少种)被不同的类装载器装载的类存放在不同的命名空间中,它们不能相互访问,除非应用程序显示地允许这么做。当编写一个Java应用程序的时候,从不同源文件装载的类可以分隔在不同的命名空间中。通过这种方法,就能够使用Java类装载器的体系结构来控制任何不同源文件中装载的代码之间的相互影响,特别是能够阻止恶意代码获取访问或破坏善意代码的权限。 Web浏览器是一个动态扩展的例子,Web浏览器使用用户定义的类装载器从网络下载用于Java applet的class文件。Web浏览器使用一个用来安装用户定义类装载器的Java应用程序。这个用户定义的类装载器通常被称为Java Applet类装载器,它知道如何向HTTP服务器请求class文件。Java Applet可以作为动态扩展的例子,因为Java应用程序并不知道它什么时候会开始从网络下载浏览器请求的class文件。只有当浏览器遇到有Java applet的页面时,才决定是否需要下载class文件。 Web浏览器启动的Java应用程序通常为每个提供class文件的网络地址分别创建不同的用户定义类装载器,因此,不同的用户定义类装载器装载不同来源的class文件。这就可以把它们分别放置在Java主机应用程序的不同命名空间之下。由于不同来源的Java applet文件放置在不同的命名空间中,恶意的Java applet代码就不会直接访问从别的地方下载的class文件。这就能够限制或阻止不同来源的代码之间的相互访问。
第三:Java class文件 Java class文件主要在平台无关性和网络移动性方面使Java更适合网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务。这种途径途径打破了C或者C++等语言所遵循的传统,使用这些传统语言写的程序通常首先被编译,然后被连接成单独的、专门支持特定硬件平台和操作系统的二进制文件。通常情况下,一个平台上的二进制可执行文件不能在其他平台上工作。而Java class文件时可以运行在任何支持Java虚拟机的硬件平台和操作系统上的二进制文件。 当编译和连接一个C++程序时,所获得的可执行二进制文件只能在指定的硬件平台和操作系统上运行,因为这个二进制文件包含了对目标处理器的机器语言。而Java编译器把Java源文件的指令翻译成字节码,这种字节码就是Java虚拟机的"机器语言"。class文件设计得紧凑,因此它们可以快速地在网络上传送。其次,由于Java程序是动态连接和动态扩展的,class文件可以在需要的时候才下载。这个特点使得Java应用程序能够安排从网络上下载class文件的时间,从而可以最大限度地减少终端用户的等待时间。
第四:Java API Java API通过支持平台无关性和安全性,使得Java适应于网络应用。Java API是运行库的集合,它提供了一套访问主机系统资源的标准方法。运行Java程序时,虚拟机装载程序的class文件所使用的Java API class文件。所有被装载的class文件(包括从应用程序中和从Java API中提取的)和所有已经装载的动态库(包含本地方法)共同组成了再Java虚拟机上运行的整个程序。 在一个平台能偶支持Java程序以前,必须在这个特定平台上明确地实现API的功能。为访问主机上的本地资源,Java API调用了本地方法。由于Java API class文件调用了本地方法,Java程序就不需要再调用它们了。通过这种方法,Java API class文件为底层主机提供了具有平台无关性、标准接口的Java程序。对Java程序而言,无论平台内部如何,Java API都会有同样的表现和可预测的行为。正是由于在每个特定的主机平台上明确地实现了Java虚拟机和Java API,因此,Java程序自身就能够成为具有平台无关性的程序。 Java API在Java安全性模型方面也有贡献。当Java API的方法进行任何有潜在危险的操作(比如进行本地磁盘写操作)之前,都会通过查询访问控制器来检验是否得到了授权。访问控制器是一个类,该类用来执行栈检验,已决定是否允许某种操作。 参考技术A 所谓核心就两个字:基础
[读书笔记]java核心技术
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内部类
已读,笔记待整理。
以上是关于Java的核心技术啥?的主要内容,如果未能解决你的问题,请参考以下文章