J2SE 5 与J2SE 1.5
J2SE 5 和J2SE 1.5其实都是指同一个版本的J2SE,前者是它的外部版本号,而后者是内部版本号.
从Java产生时,Sun公司发布了Java 1.0.而后都以1.n的形式来表示版本号.
而由于J2SE 1.5的较前面版本的变化是非常大的,可以是说是一个里程碑.
所以Sun为了强调它,另外取名J2SE 5.
J2SE 5相当于别名,而J2SE 1.5是这个版本的真实姓名.
所以当你向编译器询问版本号时,它将回答是1.5.
Sun公司的提供的联机文档使用1.5代表J2SE 5添加的新特性.
J2SE 1.5是用在比正规,严格的情况下使用,而平时生活中,我们可以把它叫做J2SE 5.
如何才算掌握Java(J2SE篇)
每次当我在编写一个Java程序时,如果是要用到Java API包中的类(或方法,常量)时候,我就会感觉写起程序来很吃力.或者说就根本写不出来了.
对于这个问题我思考了很久,后来,
在看完下面的一篇文章后,我明白了一点,是我对Java API中的常用的类,方法以及常量这些东西根本就不熟练。
如何才算掌握Java(J2SE篇) 作者:未知 时间:2005-07-24 21:13 出处:JR 责编:chinaitpower 时常看到一些人说掌握了Java,但是让他们用Java做一个实际的项目可能又困难重重,在这里,笔者根据自己的一点理解斗胆提出自己的一些对掌握Java这个说法的标准,当然对于新手,也可以提供一个需要学习哪些内容的参考.另外这个标准仅限于J2SE部分,J2EE部分的内容有时间再另说. 必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正. 2、命令: 必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:appletviewer、HtmlConverter、jar、java、javac、javadoc、javap、javaw、native2ascii、serialver,如果这些命令你没有全部使用过,那么你对java实际上还很不了解。 3、工具: 必须至少熟练使用一种IDE的开发工具,例如Eclipse、Netbeans、JBuilder、Jdeveloper、IDEA、JCreator或者Workshop,包括进行工程管理、常用选项的设置、插件的安装配置以及进行调试。 4、API: Java的核心API是非常庞大的,但是有一些内容笔者认为是必须熟悉的,否则不可能熟练的运用Java,包括: 文章来源: |
public static void main(String[] args)的含义
public static void main(String[] args)这条语句中的String[] args是什么含义呢?
干什么用呢,这个问题曾经一直困惑着我,不过,现在总算知道了.
args是命令行参数,它的数据类型是String(字符串)类. []表示数组. String[]即字符串数组.
class ArgsDemo
{
public static void main(String[] args)
{
String name=args[0];
String sex= args[1];
String age= args[2];
System.out.println("你的姓名是:"+name);
System.out.println("你的性别是:"+sex);
System.out.println("你的年龄是:"+age);
}
}
这时候,输入命令应该是java ArgsDemo 杨春 男 21,得出结果如下图所示:
杨春 男 21这三个值你可以随意更改,只要你给出了这三个值即可.
如果你只输入java ArgsDemo,得出的结果如下图所示:
java.lang.ArrayIndexOutOfBoundsException是什么意思呢?
ArrayIndexOutOfBoundsException是java.lang包下的一个异常类.它的意思是数组下标越界异常.
下面是在API 中,对这个类进行的描述:
用非法索引访问数组时抛出的异常.如果索引为负或大于等于数组大小,则该索引为非法索引.
参见下面网址:
http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/ArrayIndexOutOfBoundsException.html
关于内部类的一点思考
内部类可以理解成一个"黑盒子"
举个例子:
class Outer
{
int outer_x=100;
void test()
{
Inner inner=new Inner();
inner.display();
}
class Inner
{
void display();
{
System.out.println("display: outer_x = " + outer_x);
}
}
}
class InnerClassDemo
{
public static void main(String args[])
{
Outer outer =new Outer();
outer.test();
}
}
在这个例子中,Outer为外部类,Inner为内部类.
外部类Outer可以(通过创建Inner类对象)使用Inner类的功能.
这可以通过
Inner inner=new Inner();
inner.display();
这两条语句来体现.
但是Inner类中的变量和方法相对于Outer类来说是局部的,不可见的.Outer类看不见这些变量和方法,也就无法改变它们.
也就是说,
外部类可以使用内部类的功能,但却无法知道内部类的工作机制(Inner类的方法和变量)
数组与对象
在Java中,创建数组和对象都是通过new关键字的.它们是非常相似的
创建数组的语法:
type var-name[]=new type[size];
其中type是数据类型,var-name是数组变量.size指定数组的大小(或者说是数目,个数).
使用new type[size]创建一个新数组.把它赋值给var-name[]数组变量.
数组是作为对象实现的.
数组的一个特殊的属性是length实例变量
例如:String str[]={"one", "two", "three"};
int s=str.length;
java.lang.String类中有一个length()方法.
例如:String str="my name is yangchun";
int s=str.length();
创建对象的语法:
classname var-name=new classname();
classname是类名, var-name是一个普通的类变量
使用new classname()创建一个新对象,把它赋值给var-name类变量.
当用class关键字声明一个类时,所声明的类名就是一种自定义的数据类型.例如class Box,类名Box就是一个新的数据类型.
所以,classname实际就是一种新的自定义的数据类型.
事实上,对象是一个特殊的变量,而类(实际上是声明后的类名)是用户自定义的数据类型.
JDK命令
JDK常用命令
-
java
-
javac
-
java w
-
native2ascii
-
serialver
编译第一个Java程序
编译你的第一个Java程序
下载JDK
打开http://java.sun.com/ 网站,点击Downloads 链接,
打开记事本,复制以下代码:
/*
This is simple Java program.
Call tis file "Example.java"
*/
class Example
{
//Your program begins with a call to main().
public static void main(String args[])
{
System.out.println("This is simple Java program.");
}
}
另存为C盘,文件名为Example.java(文件后缀名一定要是java), 打开命令提示符(开始菜单->程序->附件->命令提示符或开始菜单->运行,输入cmd,点击确定).
首先输入cd/,按回车键,转到C盘
接下来输入javac Example.java,按回车键,
现在打开C盘,会发现C盘多出一个文件Example.class
最后输入java Example,按回车键
如果程序没有错误,正常输出
注意:上面的javac也就是Java编译器,而java是Java解释器,也可以理解成字节码解释器
关于javac和java的思考
一个包含Java程序的源文件经过javac编译器把它编译为class类文件(包含程序的字节码),再通过java解释器,把class文件转化为可执行代码,运行,最后输出结果.
而像C语言的非Java程序,是将源文件直接编译成可执行代码,运行,最后输出结果
字节码是一套在Java运行时系统执行的高度优化的指令集.
这个Java运行时系统就是JVM(Java Virtual Machine,Java虚拟机)
javac编译器的作用是把源文件编译成class文件,即字节码文件(准确的说一个class文件包含Java虚拟机指令(即字节码)和一个符号表以及其他的辅助信息),一旦转化为class文件,那么接下来就是JVM开始工作了.
在JVM中有一个字节码编译器----------JIT(Just In Time,即时),它的作用是将字节码动态地编译为本地代码.也就是可执行代码.
实际上,JVM就是一个字节码解释器,它把class类文件中的字节码解释成可执行代码.
前面讲到javac.exe是存放在JDK中的(事实上,你仅可以在JDK中找到它),即生成class文件的工作是由JDK来完成的.
而java.exe是分别存放于JRE和JDK中的,
所以前者的java.exe是把class文件转化为可执行代码,而后者的作用是运行,输出结果
将Java程序转化为class文件的过程,
更准确的是把Java程序中的每个单独的类转化为后缀名为.class类文件.
举个例子:
class Box
{
double width;
double height;
double depth;
}
class BoxDemo
{
public static void main(String args[])
{
Box mybox=new Box();
double vol;
mybox.width=10;
mybox.height=20;
mybox.depth=15;
vol=mybox.width * mybox.height * mybox.depth;
System.out.println("Volume is "+vol);
}
}
在这个程序中,你得把文件名命名为BoxDemo而不是Box,因为BoxDemo是程序的入口类.
当你使用javac BoxDemo.java编译这个程序时,在C盘会形成两个class类文件,分别是Box.class 和BoxDemo.class,
之所以会有两个,是因为程序中有两个类.
最终结果如上图所示.
现在新建一个文本文档,取名Box.java,剪切Box类中的代码,即下面的程序:
class Box
{
double width;
double height;
double depth;
}
别忘了保存两个文本文档哦.
删除两个class类文件.
重新打开命令提示符,输入cd/,转到C盘,
接着输入javac BoxDemo.java,同样会在C盘形成两个class类文件.
环境变量
当你使用JDK+文本编辑器(如记事本)编译Java程序时,如果没有设置的path环境变量,那么当你在命令提示符中写类似javac Example.java这样的文字时,会出现下面的错误:
'javac'不是内部或外部命令,也不是可运行的程序或批处理文件
也就是说系统不认识这个javac,因为你没有告诉系统javac.exe的存放位置
javac.exe文件是存放在C:/Program Files/Java/jdk1.6.0_03/bin中的.
java.exe分别存放在C:/Program Files/Java/jre1.6.0_03/bin和C:/Program Files/Java/jdk1.6.0_03/bin中的.
前者的JRE,即Java Runtime Environment,
中文名称为Java运行时环境,也就是JVM(Java Virtual Machine,Java虚拟机).
而后者的JDK,即Java Development Kit,中文名称为Java开发者工具包
1.6.0_03是版本号,表明使用的是最新版本JDK 1.6 Update 3,
C:/Program Files/Java是JDK和JRE的默认安装路径,
在设置path环境变量时,你必须把它改变你自己的JDK的安装路径.
而当使用Java编程工具(如Eclipse,JBuilder)时,是不需要设置环境变量的,
因为相应的Java编程工具会在你编译程序时,默默的调用javac.exe(Java编译器),产生class文件.
要想得出前面的第一个Java程序的输出结果,请按照如下的方法设置环境变量.
环境变量的设置方法:
右击我的电脑,单击属性,弹出"系统属性"窗口,单击"高级" 选项卡
单击"环境变量"按钮,弹出"环境变量"窗口
在系统变量(S)这一栏找到Path变量,双击它,弹出"编辑系统变量"窗口
在变量值这一行,填写;C:/Program Files/Java/jdk 1.6.0 _03/bin
C:/Program Files/Java是JDK和JRE的默认安装路径,
你必须把它改变为你自己的JDK的安装路径.
点击确定,在"环境变量"窗口点击确定,在"系统属性"窗口中点击确定
注意,不要删除原先的变量值.还有就是;一定要加啊!
javap 命令
这个命令的作用可以参见"JDK的命令详解"
它的功能是Java类文件解析器.我自己的理解是这个命令可能获得类的基本信息.
举个例子:
获得Example类的基本信息.
首先,在C盘新建Example.java 的记事本文档(如果这个记事本文档还存在你的磁盘上,就无需新建).
提示信息是:
ERROR:Could not find Example
翻译成中文的含义是:
错误:不能找到Example
Why?
想想看, javap是用于获得指定类的基本信息,
那么就意味着可能javap Example 这条命令中的Example是指Example.class文件,而不是Example.java
先用javac 命令获得class文件.然后再使用javap命令
可以看到,使用javap命令后,得到如下信息:
Compiled from "Example.java"
class Example extends java.lang.Object{
Example();
public static void main(java.lang.String[]);
}
从这些文字中,可以知道Example的继承java.lang.Object类.
它有两个方法:Example() 和main() 方法.
首先,所有的类(自定义的类或Java API中定义的类)都继承java.lang.Object类.
java.lang.Object是所有类的父类.
如果用一棵树来表示类的继承关系,那么,根结点肯定是java.lang.Object类.
Example()方法也称为构造函数.
在这个程序中,并没有显式的定义一个构造函数,那么会自动生成一个默认的无参数的构造函数.
至于main()方法,可以在程序中找到它.
可以看出, javap返回的是类的成员,包括方法和变量(在示例中,并未有变量).以及类的继承关系(例如, Example继承Object).
javadoc 命令
功能:
Java API文档生成器从Java源文件生成API文档HTML页。
javadoc解析Java源文件中的声明和文档注释,并产生相应的HTML页缺省,描述公有类、保护类、内部类、接口、构造函数、方法和域。
例子
import java.io.*;
/**
*This class demostrates documentation comments.
*@author Herbert Schildt
*version 1.2
*/
public class SquareNum
{
/**
*This method returns the square of num.
*This is a multiline description. You can use
*@param num The value to be squared.
*@return num squared.
*/
public double square(double num)
{
return num * num;
}
/**
*This method inputs a number from the user.
*@return The value input as a double.
*@exception IOException On input error.
*@see IOExcetption
*/
public double getNumber() throws IOException
{
//create a BufferedReader using System.in
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader inDate=new BufferedReader(isr);
String str;
str=inDate.readLine();
return (new Double(str).doubleValue());
}
/**
*This method demostrates square().
*@param args Unsed.
*@return Nothing.
*@exception IOException On input error.
*@see IOException
*/
public static void main(String args[]) throws IOException
{
SquareNum ob=new SquareNum();
double val;
System.out.println("Error value to be squared: ");
val=ob.getNumber();
val=ob.square(val);
System.out.println("Squared value is "+val);
}
}
在C盘生成了HTML文档.
下图显示了javadoc的用法:
用法:javadoc [选项] [软件包名称] [源文件] [@file]
-overview <文件> 读取 HTML 文件的概述文档
-public 仅显示公共类和成员
-protected 显示受保护/公共类和成员(默认)
-package 显示软件包/受保护/公共类和成员
-private 显示所有类和成员
-help 显示命令行选项并退出
-doclet <类> 通过替代 doclet 生成输出
-docletpath <路径> 指定查找 doclet 类文件的位置
-sourcepath <路径列表> 指定查找源文件的位置
-classpath <路径列表> 指定查找用户类文件的位置
-exclude <软件包列表> 指定要排除的软件包的列表
-subpackages <子软件包列表> 指定要递归装入的子软件包
-breakiterator 使用 BreakIterator 计算第 1 句
-bootclasspath <路径列表> 覆盖引导类加载器所装入的
类文件的位置
-source <版本> 提供与指定版本的源兼容性
-extdirs <目录列表> 覆盖安装的扩展目录的位置
-verbose 输出有关 Javadoc 正在执行的操作的消息
-locale <名称> 要使用的语言环境,例如 en_US 或 en_US_WIN
-encoding <名称> 源文件编码名称
-quiet 不显示状态消息
-J<标志> 直接将 <标志> 传递给运行时系统
通过标准 doclet 提供:
-d <directory> 输出文件的目标目录
-use 创建类和包用法页面
-version 包含 @version 段
-author 包含 @author 段
-docfilessubdirs 递归复制文档文件子目录
-splitindex 将索引分为每个字母对应一个文件
-windowtitle <text> 文档的浏览器窗口标题
-doctitle <html-code> 包含概述页面的标题
-header <html-code> 包含每个页面的页眉文本
-footer <html-code> 包含每个页面的页脚文本
-top <html-code> 包含每个页面的顶部文本
-bottom <html-code> 包含每个页面的底部文本
-link <url> 创建指向位于 <url> 的 javadoc 输出的链接
-linkoffline <url> <url2> 利用位于 <url2> 的包列表链接至位于 <url> 的文
档
-excludedocfilessubdir <name1>:..排除具有给定名称的所有文档文件子目录。
-group <name> <p1>:<p2>..在概述页面中,将指定的包分组
-nocomment 不生成描述和标记,只生成声明。
-nodeprecated 不包含 @deprecated 信息
-noqualifier <name1>:<name2>:...输出中不包括指定限定符的列表。
-nosince 不包含 @since 信息
-notimestamp 不包含隐藏时间戳
-nodeprecatedlist 不生成已过时的列表
-notree 不生成类分层结构
-noindex 不生成索引
-nohelp 不生成帮助链接
-nonavbar 不生成导航栏
-serialwarn 生成有关 @serial 标记的警告
-tag <name>:<locations>:<header> 指定单个参数自定义标记
-taglet 要注册的 Taglet 的全限定名称
-tagletpath Taglet 的路径
-charset <charset> 用于跨平台查看生成的文档的字符集。
-helpfile <file> 包含帮助链接所链接到的文件
-linksource 以 HTML 格式生成源文件
-sourcetab <tab length> 指定源中每个制表符占据的空格数
-keywords 使包、类和成员信息附带 HTML 元标记
-stylesheetfile <path> 用于更改生成文档的样式的文件
-docencoding <name> 输出编码名称
appletviewer 命令
使用JDK+文本编辑器的方式处理Java中的Applet(Applet是在Web浏览器中运行的小程序).
举个例子
import java.awt.*;
import java.applet.*;
/*
<applet code="Rectangles" width=300 height=200>
</applet>
*/
public class Rectangles extends Applet
{
public void paint(Graphics g)
{
g.drawRect(10,10,60,50);
g.fillRect(100,10,60,50);
g.drawRoundRect(190,10,60,50,15,15);
g.fillRoundRect(70,90,140,100,30,40);
}
}
上面这段程序是Applet(小应用程序)的一个例子,正确的输出结果如下图所示:
图A
而使用命令提示符,得到的结果如下图所示:
Exception in thread “main” java.lang.NoClassDefFoundError: Rectangles
这一句直接翻译的意思是:
异常在线程”main” java.lang.NoClassDefFoundError: Rectangles
(Rectangles就是上面创建的类.)
java.lang.NoClassDefFoundError是什么意思呢?
首先java.lang是API中的一个包,而NoClassDefFoundError是这个包下的一个错误类,
下面是在API中,对这个类进行的描述:
当 Java 虚拟机或 ClassLoader实例试图在类的定义中加载(作为通常方法调用的一部分或者作为使用 new表达式创建的新实例的一部分),但无法找到该类的定义时,抛出此异常。
参见下面网址:
http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/NoClassDefFoundError.html
java.exe只能处理由main()函数作为入口的Java程序,
简单理解就是Java程序必须有一条这样的语句:public static void main(String args[])
而在Applet中是根本不需要这条语句的。
事实上,在Java中,main()函数已经很少被使用了,只有在一些非常简单的程序中才能用到.而这些简单的程序一般都是用于演示的目的.
使用java是行不通的,但是可以使用appletviewer -debug Rectangles.java
appletviewer.exe是存放在C:/Program Files/Java/jdk1.6.0_03/bin中的,为Java Applet小程序查看器.
下图中详细显示中appletviewer的用法
jdb也是存放在C:/Program Files/Java/jdk1.6.0_03/bin中的
你会发现等上很长一段时间什么反应都没有,这说明这个方法也是行不通的。
这时候,再来第二个方法:
把Rectangles.java文件的后缀名改成html,也就是Rectangles.html.
首先第一步,向命令提示符键入cd/,转到C盘.
第二,键入javac Rectangles.java ,转化为Rectangles.class类文件.
注意,在这一步,Rectangles文件的后缀名应该是java,而不是html.
第三步,把后缀名java改成html,打开这个文件
右击允许阻止的内容(请放心,这不会对你的系统产生任何影响)
可以看到与图A的结果是很接近的,所不同的是,前面是在applet查看器中运行的,而后者是html.
所以现在我们关闭Rectangles.html文件.
切换到刚才使用的命令提示符,输入appletviewer Rectangles.html
按回车键,弹出一个窗口,如下图
发现与图A的结果基本是一致的.
在Rectangles.java中,有这样一条语句,
/*
<applet code="Rectangles" width=300 height=200>
</applet>
*/
首先/* . . .*/ 在Java是注释,也可以把它改成下面的形式:
// <applet code="Rectangles" width=300 height=200> </applet>
而<applet> . . .</applet>其实是<applet>标签.
为什么会出现这个标签呢,这其实与Java Plug-in (插件)有关.
首先, Applet是在Web浏览器中运行的小程序,这就需要浏览器能够支持Applet ,
在早期的时候,基本上只有网景浏览器(Netscape ,可怜啊!现在这个浏览器的市场占有率不到1%),而这个浏览器是可以支持Applet,
所以,Sun公司也就没有开发插件的必要了.
当然了,Sun公司自己也有开发一款浏览器,名字叫做HotJava
而随着微软件的IE浏览器的出现, Netscape的被淘汰,浏览器软件的竞争可以说是非常的激烈,
现在又有Mozilla FireFox(火狐),傲游等等.
这样就出现了一个问题,Sun公司并不能保证所有的游览器都能支持Applet .
于是插件也就出现了.
这就有今天的<applet>标签和Java(TM) Plug-in HTML转换程序以及HtmlConverter 命令
在JDK中自带了Java插件,
HtmlConverter 命令
输入HtmlConverter (大小写可以忽略),弹出Java(TM) Plug-in HTML转换程序.
在里Plug-in是插件的意思.
点击编辑->选项
弹出"高级选项"窗口
点击转换按钮,弹出如下窗口:
关于HtmlConverter命令还在进一步研究中. . . . .
在Rectangles.java中,是一个applet小程序,现在来看看使用HtmlConverter命令的结果:
在”指定文件或目录路径”这一栏的右侧点击”浏览”, 找到Rectangles.java并且点击”打开” 按钮.
最后点击”转换”按钮,弹出如下窗口:
点击”完成”.
这时候,打开Rectangles.java查看一下:
原来的applet脚本
/*
<applet code="Rectangles" width=300 height=200>
</applet>
*/
变成了下面的内容:
/*
<!--"CONVERTED_APPLET"-->
<!-- HTML CONVERTER -->
<object
classid = "clsid:8AD 9C 840-044E-11D1-B3E9 -00805F 499D93"
codebase = "http://java.sun.com/update/1.6.0/jinstall-6u30-windows-i586.cab#Version=6,0,0,5"
WIDTH = 300 HEIGHT = 200 >
<PARAM NAME = CODE VALUE = "Rectangles" >
<param name = "type" value = "application/x-java-applet;version=1.6">
<param name = "scriptable" value = "false">
<comment>
<embed
type = "application/x-java-applet;version=1.6" /
CODE = "Rectangles" /
WIDTH = 300 /
HEIGHT = 200
scriptable = false
pluginspage = "http://java.sun.com/products/plugin/index.html#download">
<noembed>
</noembed>
</embed>
</comment>
</object>
<!--
<APPLET CODE = "Rectangles" WIDTH = 300 HEIGHT = 200>
</APPLET>
-->
<!--"END_CONVERTED_APPLET"-->
*/
这部分内容多出的<object>. . .</object>和<embed>. . .</embed>标记.
JDK的命令详解
这篇文章是转载的,作者不详
rmic 功能说明: |
rmid |
rmiregistry |
serialver |
jarsigner |
keytool |
native2ascii |
appletviewer |
extcheck |
jar |
javadoc -windowtitle,则 Javadoc 对该选项使用 -doctitle 的值。 |
javah |
javap |
关于static
如果你留心观察,会发现,在Java API中, 许多类的方法和常量都声明为static,这是为什么呢?
而我们可以使用classname.method()这样的语法形式使用API中类的方法和常量.
其中method是类的方法.
举个例子:
class MathDemo
{
double CircleArea; //声明圆面积变量
double SquareRoot; //声明平方根变量
void showArea(double i)
{
CircleArea = Math.PI * i * i;
System.out.println("Circle Area is: " + CircleArea);
}
void showSqrt(double i)
{
SquareRoot=Math.sqrt(i);
System.out.println("Square Root is: " + SquareRoot);
}
public static void main(String args[])
{
MathDemo math=new MathDemo();
math.showArea(6);
math.showSqrt(9);
}
}
http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/Math.html#sqrt(double)
若没有使用static关键字,那么使用对象去访问方法或成员变量,这比直接用类去访问方法或成员变量要麻烦,繁琐.
注意上面程序中的Math.PI和Math.sqrt(i)部分,
Math为java.lang包下的一个类,
PI(PI常量就是圆周率)为Math类下的一个静态常量.sqrt()为Math类下的一个静态方法.
正因为方法和常量声明为静态的(static)的,所以可以直接用类去访问方法和常量.
如果这个常量并非是静态的.那么你只能通过如下的方法去访问方法和常量:
Math m=new Math();
m.PI;
m.sqrt(i);
相比之下,你更喜欢哪一种的方式呢?
关于Math类,可以参考下列网址:
http://gceclub.sun.com.cn/Java_Docs/html/zh_CN/api/java/lang/Math.html
对MathDemo.java的修改
class MathDemo
{
static double CircleArea; //声明圆面积变量
static double SquareRoot; //声明平方根变量
static void showArea(double i)
{
CircleArea = Math.PI * i * i;
System.out.println("Circle Area is: " + CircleArea);
}
static void showSqrt(double i)
{
SquareRoot=Math.sqrt(i);
System.out.println("Square Root is: " + SquareRoot);
}
public static void main(String args[])
{
showArea(6);
showSqrt(9);
}
}
注意这段代码与上面的区别.在方法showArea()和showSqrt(),变量CircleArea和SquareRoot前面都加上了static关键字,
结果是不需要创建MathDemo对象,就可以直接访问这两个方法.
可以看出,程序的输出结果是和前面的完全一样的.
如果变量CircleArea和SquareRoot前面没有加static,会出什么情况呢?看下图
MathDemo.java:7: 无法从静态上下文中引用非静态 变量 CircleArea
原因如下:
声明为static的方法有几条限制:
-
仅可以调用其他 static 方法
-
只能访问 static 数据 说简单一些就是声明为 static 的变量
-
不能以任何方式引用 this 或 super
关于静态方法的一点思考
举个例子:
class Box
{
static double width;
static double height;
static double depth;
Box(double w,double h,double d)
{
width=w;
height=h;
depth=d;
}
static double Volume()
{
return width * height * depth;
}
}
class BoxDemo1
{
public static void main(String args[])
{
double vol;
vol=Box.Volume();
System.out.println("Volume is: " + vol);
}
}
当我编出这个程序时,我首先判断这段程序会出现编译错误(也就是说但使用javac BoxDemo.java这条语句后,就会出现错误).
但是结果是,它可以运行而且有输出.下面是输出结果:
结果是0.0.
我明白了.
在vol=Box.Volume();这条语句中,Box实际上指的是new Box(),即创建了一个对象.
Box()是一个没有参数的构造函数.
构造函数初始化一个对象,并且把类中的所有成员变量(即例子中的变量width、height、depth)自动初始化为0.
也就是得到这样的结果:
width = height = depth =0;
所以当调用静态方法Volume()时,返回的三个变量相乘的结果是0.0
自然输出也就是0.0了.
这时候显式声明的构造函数就不起作用.
显式的构造函数就是例子中的
Box(double w,double h,double d)
{
. . .
}
部分.
如果想得到一个非0的结果,可以这样做:
Box mybox = new Box(10,20,15);
mybox.Volume();
第一个简短的包示例
package MyPack;
class Balance
{
String name;
double bal;
Balance(String n,double b)
{
name=n;
bal=b;
}
void show()
{
if(bal<0)
System.out.println("-->");
System.out.println(name + ": $" + bal);
}
}
class AccountBalance
{
public static void main(String args[])
{
Balance current[]=new Balance[3];
current[0]=new Balance("K.J.Fielding",123.23);
current[1]=new Balance("Will Tell",157.02);
current[2]=new Balance("Tom Jackson",-12.33);
for(int i=0;i<3;i++) current[i].show();
}
}
javac -classpath C:/MyPack AccountBalance.java
-classpath设置类文件的存放路径.在这里是C:/MyPack.
MyPack就是程序中自定义的包名.
在执行下面的java命令前,先使用cd/重新转到C盘.
java MyPack.AccountBalance
在这里,使用包名.类名的形式.
java命令后面跟着的是class类文件名(即后缀名为.class的文件).
MyPack是一个包目录,里面有这两个class文件.
在这里,类AccountBalance和Balance是在MyPack包中的.
当使用java MyPack.AccountBalance这条命令时,意思是说执行MyPack包中的名称为AccountBalance的类文件.
而这里MyPack包具体就是MyPack文件夹.
程序的正确输出结果如下图所示:
如果在使用java命令前不转到C盘,那么会出现下面的错误:
Exception in thread "main" java.lang.NoClassDefFoundError: MyPack/AccountBalance
对第一个包示例的改变
现在我对上面的程序做一个小小的改变:
在C盘新建一个AccountBalance.java的记事本文档.
复制下面的代码:
import MyPack.Balance;
class AccountBalance
{
public static void main(String args[])
{
Balance current[]=new Balance[3];
current[0]=new Balance("K.J.Fielding",123.23);
current[1]=new Balance("Will Tell",157.02);
current[2]=new Balance("Tom Jackson",-12.33);
for(int i=0;i<3;i++) current[i].show();
}
}
在MyPack文件夹中(如果删除了请重新新建一个即可)新建一个Balance.java的记事本文档.
复制下面的代码:
package MyPack;
public class Balance
{
String name;
double bal;
public Balance(String n,double b)
{
name=n;
bal=b;
}
public void show()
{
if(bal<0)
System.out.println("-->");
System.out.println(name + ": $" + bal);
}
}
首先Balance类是自定义包MyPack下的一个类,
所以如果想要使用Balance类来创建对象,就必须导入这个类.
语句import MyPack.Balance;的作用就是导入Balance类.
import语句的一般形式:
import pkg1[.pkg2].(classname | *);
pkg1和pkg2是包名,它们可以创建包的层次.
classname | *的含义是显式指定类名或者导入包中的所有类.
import不仅可以导入自定义的包(如程序中的MyPack包),也可以导入Java API中的包.
Java API中的包是已经定义好的,可以直接使用的包.这些定义的工作是由软件来实现的.
改变的Balance.java中的类Balance,构造函数Balance(),以及show()方法都使用public方法,为什么呢?
先来看看没有加public 产生的结果:
这是在Balance类的声明前面加了public后的结果:
在Java中有4个访问限定符:public (公有), protected (保护) , private (私有) 和package (包).
其中, package (包)访问限定符是默认的限定符,
当一个成员(类,变量,常量,方法)声明的前面没有加任何限定符(public , protected , private中的任何一个)时,就是默认的访问限定符.
例如,前面程序中,在类AccountBalance的声明前面并没有加任何限定符.
类AccountBalance的前面并没有加任何限定符,所以它的访问级别是包.
在AccountBalance.java中,并没有定义任何包,所以类AccountBalance会被放入一个默认的包中,而这个包是没有名字的.
同样的,如果Balance类前面没有加public限定符,那么就是包访问级别.
这也就意味着只有同一个包中的类可以访问Balance类.
上图中的"AccountBalance.java:1: MyPack.Balance在MyPack中不是公共的;无法从外部软件包中对其进行访问"这一句说的正是这个意思.
同样的,构造函数Balance()和show()方法,如果没有加public限定符,也就是包访问级别.
这也意味着只有同一个包中的类可以访问构造函数和show()方法.
如果构造函数和show()方法被声明为private的, 那么构造函数和show()方法仅仅针对Balance类是可见的.即使是同一包中的类,也不可能访问.
上图中的" AccountBalance.java:7: Balance(java.lang.String,double)在MyPack.Balance中不是公共的;无法从外部软件包中对其进行访问"
和 "AccountBalance.java:10: show()在MyPack.Balance中不是公共的;无法从外部软件包中对其进行访问"
这两句说的正是这个意思.
最后一点 , 事实上 , 一个类仅有 2 种访问级别:默认 和 public
运行
进入命令提示符,输入cd/转到C盘,接着输入javac AccountBalance.java ,
这时会在C盘和MyPack文件夹中分别形成两个AccountBalance.class和Balance.class的类文件.
,最后输入java AccountBalance. 程序的输出结果如下图所示:
关于接口
在接口中定义的方法实际上是抽象方法.
在接口中定义的方法return-type method-name(parameter-list);实际上是抽象方法,
它可以表示成如下的形式:
abstract return-type method-name(parameter-list);
而在接口中定义的方法是可以省略abstract关键字的.
在抽象类(在类声明前面加abstract的类)中的抽象方法是不能省略这个关键字的.
接口与抽象类(抽象类不能创建对象,也就是说不能通过new来创建对象)是相似的,它们都是抽象的机制,
所不同的是,一个类可以实现任意数目的接口,而只能一个超类(在这里的超类指抽象类)
接口基本上等同于抽象类,但是接口的范围更广泛.
在Java中,不支持多重继承,即多个父类,一个子类(n对1)的情况.
只可以有一个父类,一个子类(1对1)或者一个父类,多个子类(1对n)的情况. (在C++中是支持多重继承的)
可以说,接口实际上是多重继承的另外一种方式
把接口看作抽象类,一个类可以有多个接口,也就是可以有多个超类(或称父类)
举个例子:
import static java.lang.Math.PI;
interface Area
{
double area(double a);
double area(double a,double b);
double area(double a,double b,double c);
}
class AreaDemo implements Area
{
public double area(double a)
{
return PI *a *a;
}
public double area(double a,double b)
{
return a*b;
}
public double area(double a,double b,double c)
{
return (a + b) * c / 2.0;
}
public static void main(String args[])
{
AreaDemo ad=new AreaDemo();
System.out.println("圆的面积是:");
System.out.println(ad.area(3));
System.out.println("矩形的面积是:");
System.out.println(ad.area(3,4));
System.out.println("梯形的面积是:");
System.out.println(ad.area(3,4,5));
}
}
值的注意的是,在C盘形成了两个class类文件,其中 一个是Area.class
也就是说,接口在被转化编译后,是以类文件的形式来实现它.
如果将上面程序中的红色部分的public都去除,那么出现的错误如下图所示:
AreaDemo.java:18: AreaDemo 中的 area(double,double,double) 无法实现 Area 中的 area(double,double,double);正在尝试指定更低的访问权限;为 public
抽象类的原则
▲ 包含一个或多个抽象方法的类必须被声明为抽象的
声明一个抽象类的方法:在class前加abstract关键字
▲ 抽象类不能有对象,即一个抽象类不能通过new直接实例化.这样的对象是无用的.
可以声明抽象类的变量.
▲ 不能声明抽象构造函数或抽象静态方法
▲ 所有抽象类的子类都必须实现超类中的所有抽象方法或者本身也声明为abstract
重载和方法重写的区别
▲ 重载要求(方法的)参数的数据类型或个数中有一个不同即可.并且返回类型对重载没有影响.
方法重写要求参数的数据类型和个数均相同.并且返回类型也要相同.
▲ 重载针对单个类而言
方法重写发生在继承中(子类中的方法覆盖超类中的同名方法)
▲ 重载只适用于方法
重写也可以是成员变量的重写
▲ 也可以重载构造函数
方法重写只针对方法,但不包括构造函数.
相同点
要求方法的名称相同
继承
继承是作用于类的外部。它是类与类之间进行信息交流的手段.
继承的原则
▲ 超类变量可以引用子类对象,此变量仅能访问被子类继承的成员,不能访问由子类自己定义的成员.
下面的原则证明了这点.
▲ 每个子类都有与父类不同的专有(或者说惟一)的属性,而父类是不知道这些专有属性的,即使是引用子类对象.
超类不知道子类添加了什么
▲ super
super()总是引用调用类之上的直接超类的构造函数.即使在多层次中也是如此.
super()必须永远是子类构造函数内所执行的第一条语句.
super.member
member可以是方法,也可以是实例变量.
这种形式的super多用于超类成员被子类中同名的成员隐藏的情况(用于方法重写中.子类的成员覆盖父类中的同名成员)
这种形式可以用来调用被隐藏的成员(即父类的成员)
▲ 超类将成员(private和构造函数除外)复制给子类,使子类拥有这些成员,并且可以通过子类对象直接使用这些成员.
▲ 在Java中,不支持多个超类到单个子类的继承.这种形式的继承被称为多重继承.
一个子类可以是另一个类的超类.
▲ 在一个类层次中,构造函数按派生顺序,即从超类到子类的顺序被调用
不管是否使用了super(),这个顺序是不变的