将jre由jdk路径下的jre改为外部的jre即可,具体做法为:
Project -> Properties -> Java Build Path -> Libraries,选中JRE System Library,然后Remove; 再点击Add Library -> JRE System Library -> next,选择Alternatie JRE,点击Installed JREs,选择jdk同级目录下的jre即可,然后依次点击Apply -> ok即可。
深入理解JDK、JRE(两套)、JVM、以及不同目录下的java.exe
1、jdk下bin目录里的java.exe与外部jre中的java.exe
jdk里的java.exe和jre中的java.exe其实是一样的,但我们在运行的时候用的却是优先使用外部jre中的java.exe,即使我们安装了JDK且也配置了环境变量。
首先,我们看下JDK的安装过程中发生了什么事,安装JDK时一定会在其子目录下面安装一个JRE,同时在安装的过程也会询问你是否要安装一 个外部的JRE,如果我们选择安装则就同时拥有了两个jre,这两个JRE其实本质上是没有任何分别的。
最主要的区别在于:JDK目录里面的JRE主要是用来运行JDK自带的那些工具的(Bin目录下);外部的JRE在安装的时候会自动注册到操作系统的path里面,一般是:System32文件夹下 (该文件夹下包含:java.exe javaw.exe javaws.exe 三个文件),但在我的电脑属性高级系统设置环境变量系统变量中的 path中并没有包含该命令的路径值。
因此我们只要安装了外部的JRE(即使JDK没有安装,环境变量没有配置),则运行Java程序时都是用的外部JRE的java.exe程序来运行的(即使安装了JDK且配置了环境变量)(系统的默认path具有优先)。
2、简单的说JDK是面向开发人员
JDK(JAVA Develop Kit,JAVA开发工具包)提供了Java的开发环境和运行环境,主要用于开发JAVA程序,面向Java程序的开发者;JRE(JAVA Runtime Environment,JAVA运行环境)提供了Java的运行环境,主要用于执行JAVA程序,面向Java程序的使用者。
一般情况下,每个JDK里面包含两套JRE。以JDK jdk1.6.0_22(默认安装路径是C:Program FilesJava)为例,在C:Program FilesJavajdk1.6.0_22目录下有一个JRE,在C:Program FilesJava目录下也有一个JRE。
当用户只需要执行 java 的程序时,那么使用 c:program filesjavajre 下的 jre;当用户是 java 程序员,需要 java 开发环境,系统就会优先去找"java 、 javac "这些命令本身的目录或者它们的父目录的 jre,java.exe依据以下顺序来寻找JRE:自己的目录下有没有JRE目录;父目录下有没有JRE目录;查询注册表HKEY_LOCAL_MACHINESoftwareJavaSoftJava Runtime Environment
所以java.exe的执行结果与我们电脑里哪一个java.exe(搜索一下就会发现我们电脑里面也不止一个java.exe)被执行以及哪套JRE来执行JVA程序有很大的关系。
另外,java.exe在找到合适的JRE以后,还有一个验证版本的程序,也就是java.exe与JRE的版本一致才可以执行,如果出现版本不一致的问题,一定要记得两件事情:
(1)哪一个java.exe被执行;(2)java.exe找到哪一套JRE
3、JVM(JAVA Virtual Machine,JAVA虚拟机)是JRE的一部分,JRE是JVM的补充。
那么JVM到底在哪里呢?C:Program FilesJavajdk1.5.xjrein,会看到client和server两个目录,在这两个目录中分别可以看到jvm.dll,这就 是我们所说的JVM之所在;另外一套jre,C:Program FilesJava目录下的JREin,client目录下,可以看到jvm.dll
JAVA可视化闹钟源码
package Clock; import sun.audio.AudioPlayer; import sun.audio.AudioStream; import javax.swing.*; //awt和swing是做界面用的类 import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.*; //io流用于读写文件,包括增删闹钟、打开铃声等等 import java.util.Calendar; //用于获取当前时间的类 import java.util.GregorianCalendar;//标准阳历 import java.util.StringTokenizer; //读取文件转换成计算机语言用的类 /* 1 计时器 要求1:一个带有可视化界面的钟表。 要求2:可以添加若干个闹钟。 要求3:具备持久化功能,关闭程序不能丢失闹钟。 要求4:闹钟是可编辑,可删除的。 实现:先创建一个面板显示闹钟,面板内创建按钮增加闹钟,按钮查看闹钟,按钮删除闹钟 线程间隔1s读取时间和闹钟比较 */ public class ClockTry extends JFrame implements Runnable { /* 成员变量 */ private JPanel xx; //总的面板 private JComboBox ho; //hour选择时间的下拉框 private JComboBox mi; //min选择分钟的下拉框 private JButton tjnz; //添加闹钟的按钮 private JButton schour; //删除闹钟的按钮 private String filename = "D://homework//java//Gui//src//Clock//0.wav"; //所有的路径改这两个地方就可以了 private String pathname = "D://homework//java//Gui//src//Clock//nz.txt"; // 绝对路径或相对路径都可以,写入文件时演示相对路径,读取以上路径的input.txt文件 private int HOUR; //定义HOUR用于接收按钮按下从下拉框中获取的数据 private int MIN; //同上 int x = 100, y = 100, r = 100; // (x,y)为(0,0)点,表示原点 int h, m, s; // 时,分,秒 double rad = Math.PI / 180; // 1° private String[][] str= new String[100][2]; //定义二维数组,用于存储以及对小时和分针的操作,暂定为100个闹钟于是定义为【100】【2】 /** *读取文件,每次的增删都需要对数据进行读取,将数据写在面板上也需要读取数据 */ public void readFile() { try (FileReader reader = new FileReader(pathname); //创建一个FilReader对象,将文件读出来,相当于请教一个当地人,当地人了解本地文化,但是语言不通听不懂 BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言,相当于请一个翻译,把当地人读取的东西转换成计算机能懂的东西 ) { String line; int i =0; while ((line = br.readLine()) != null) { //翻译理解的东西存到line里面 int j =0; StringTokenizer st = new StringTokenizer(line, ":"); //重点:由于存储数据时都是时间,道理来说都是数字,无法区分小时部分和分钟部分 while (st.hasMoreTokens()){ //每读取一次读到的内容 //所以这里用分割符“:”来分割,相应的,后面的写入文件也应该已“:”分割进行写入 str[i][j]=st.nextToken(); //把读到的内容存储在数组里面便于后面的操做——增删 j++; //包括上面的j=0,是将for循环拆分放进while循环中,要不然循环写起来也很麻烦 } //System.out.print(str[i][0]+":"+str[i][1]); 写的时候用来在控制台打印查看效果 //System.out.println(); i++; j = 0; } } catch (IOException e) { e.printStackTrace(); //try……catch抛出异常 } } /** * 写入TXT文件 */ public void writeFile() { HOUR = Integer.valueOf(ho.getSelectedIndex()); //获取下拉框中的值,存储到HOUR中 MIN = Integer.valueOf(mi.getSelectedIndex()); String x = HOUR + ":" + MIN; try (FileWriter writer = new FileWriter(pathname,true); //同上面的读取,本地人写入,注意:后面的append:true是表示不是重新写,而是在后面追加 BufferedWriter out = new BufferedWriter(writer) //翻译一下再写入 ) { out.write(HOUR + ":" + MIN + " "); //这里写入的时候把:写进去了! out.flush(); // 把缓存区内容压入文件,计算机的存储过程,存在缓存区再写入文件 JOptionPane.showMessageDialog(null,"闹钟添加成功!","添加闹钟提醒",JOptionPane.INFORMATION_MESSAGE); //提示框:添加闹钟成功 } catch (IOException e) { e.printStackTrace(); } } /** * 删除闹钟,实际上是先将要删除的数据找到移除数组,再将数组重新写入,所以要先读取文件,再重新写入 */ public void shanchuFile() { HOUR = Integer.valueOf(ho.getSelectedIndex()); MIN = Integer.valueOf(mi.getSelectedIndex()); try (FileWriter writer = new FileWriter(pathname); //没有append:true,表示重新写! BufferedWriter out = new BufferedWriter(writer) ) { readFile(); for (int i = 0; i < 100; i++) { if (Integer.valueOf(str[i][0])==HOUR && Integer.valueOf(str[i][1])==MIN){ continue; } else{ out.write(str[i][0]+":"+str[i][1]+" "); // 即为换行 } } //out.write("1"+"1"+" "); // 即为换行 out.flush(); // 把缓存区内容压入文件 } catch (IOException e) { e.printStackTrace(); }catch (NumberFormatException e){ System.out.println("this isn't exist!"); JOptionPane.showMessageDialog(null,"该闹钟已删除!","删除闹钟提醒",JOptionPane.INFORMATION_MESSAGE); //弹窗提示 } } /* 初始化函数 */ public void init() { Calendar now = new GregorianCalendar(); //获取当前时间 /* * GregorianCalendar(标准阳历) * 是Calendar(日历)【国际环境下都能运行的程序】 * 的子类 */ s = now.get(Calendar.SECOND) * 6; // 秒针转换成角度:1秒,秒针动一次,转动6° m = now.get(Calendar.MINUTE) * 6; // 分针转换为角度:1分,分针动一次,转动6° h = now.get(Calendar.HOUR) * 30 + now.get(Calendar.MINUTE) / 12 * 6; // 先把分化为小时,再乘以6°,因为分针转12°,时针才会转1°,一小时中间有5格,数学问题 /* * Calendar.HOUR 显示范围:1-12(无论AM还是PM) Calendar.HOUR_OF_DAY 显示范围:1-24(包括PM */ Thread t = new Thread(this); //添加线程,线程目标是整个程序,this t.start(); //线程就绪 } public void paint(Graphics g) { //awt中的方法,因为要时时显示闹钟,所以不得不使用绘画的方式,不断重绘 super.paint(g); /* * paint(g)函数会重绘图像,要加上super.paint(g),表示在原来图像的基础上,再画图。 * 如果不加super.paint(g),重绘时,会将原有的绘制清空,再根据paing(g)函数绘制。 */ g.setColor(Color.BLACK); //设置画笔颜色——黑色 g.drawOval(x, y, r * 2, r * 2);// 画表 /* drawOval(x,y,width,height)以矩形恰好框住椭圆,矩形左上角的顶点坐标为(x,y) */ // 秒针 int x1 = (int) (90 * Math.sin(rad * s)); int y1 = (int) (90 * Math.cos(rad * s)); g.drawLine(r+x, r+y, r+x + x1, r +y- y1); /* drawLine(a,b,c,d) (a,b)为起始坐标 (c,d)为终点坐标 */ // 分针 x1 = (int) (80 * Math.sin(rad * m)); y1 = (int) (80 * Math.cos(rad * m)); g.drawLine(r+x, r+y, r +x+ x1, r+y - y1); // 时针 x1 = (int) (60 * Math.sin(rad * h)); y1 = (int) (60 * Math.cos(rad * h)); g.drawLine(r+x, r+y, r+x + x1, r +y- y1); // 画数字 int d = 30; for (int i = 1; i <= 12; i++) { x1 = (int) ((r - 10) * Math.sin(rad * d)); y1 = (int) ((r - 10) * Math.cos(rad * d)); g.drawString(String.valueOf(i), r+x + x1, r+y - y1); //字符型的数据才能画 d += 30; } // 画刻度 d = 0; for (int i = 1; i <= 60; i++) { x1 = (int) ((r - 2) * Math.sin(rad * d)); y1 = (int) ((r - 2) * Math.cos(rad * d)); g.drawString(".", r+x + x1, r +y- y1); //画的是点,表示刻度 d += 6; } // 显示时间 Calendar now1 = new GregorianCalendar(); int a, b, c; a = now1.get(Calendar.HOUR_OF_DAY); //获取当前的小时 b = now1.get(Calendar.MINUTE); //获取当前的分钟 c = now1.get(Calendar.SECOND); //获取当前的秒钟 g.drawString(a + ":" + b + ":" + c, 175, 330); //将时间也画到面板上 g.drawString("全部闹钟:",100,350); //全部闹钟 try (FileReader reader = new FileReader(pathname); BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言 ) { String line; int i =0; while ((line = br.readLine()) != null) { int j =0; StringTokenizer st = new StringTokenizer(line, ":"); while (st.hasMoreTokens()){ str[i][j]=st.nextToken(); j++; } g.drawString(str[i][0]+":"+str[i][1]+" ",180+(i/10)*70,350+15*(i-(i/10)*10)); //貌似重新写了一下readfile的方法,其实是有区别的,这里是读取以后画出来 //qbnz.setText(str[i][0]+":"+str[i][1]+" "); //System.out.print(str[i][0]+":"+str[i][1]); //System.out.println(); i++; j = 0; } } catch (IOException z) { z.printStackTrace(); } } // 实现Runnable,实现implement Runnable就务必实现run方法,使线程运行 public void run() { while (true) { try { Thread.sleep(1000);// 间隔一秒 } catch (Exception ex) { } s += 6; // 秒针每次走6° if (s >= 360) { s = 0; // 秒针归零 m += 6; if (m == 72 || m == 144 || m == 288) { h += 6; // 分针走72°,时针走6° 分针的12倍,时针走一次 } if (m >= 360) { m = 0; // 分针归零 h += 6; } if (h >= 360) { h = 0; // 时针归零 } } this.repaint(); // 重新绘制 //this.readFile(); this.alert(); //将闹钟加入到线程当中 }} public void alert(){ Calendar now1 = new GregorianCalendar(); int a, b; a = now1.get(Calendar.HOUR_OF_DAY); b = now1.get(Calendar.MINUTE); //这里没有获取秒针是因为闹钟不看秒针。。。。。 try (FileReader reader = new FileReader(pathname); BufferedReader br = new BufferedReader(reader) // 建立一个对象,它把文件内容转成计算机能读懂的语言 ) { String line; String[][] str= new String[100][2]; int i =0; while ((line = br.readLine()) != null) { int j =0; StringTokenizer st = new StringTokenizer(line, ":"); while (st.hasMoreTokens()){ str[i][j]=st.nextToken(); j++; } if (a==Integer.valueOf(str[i][0]) && b==Integer.valueOf(str[i][1])){ //读取后与获得的时间比较,如果闹钟存在,就响 try{ InputStream in = new FileInputStream("D://homework//java//Gui//src//Clock//0.wav");//FIlename 是你加载的声音文件如(“game.wav”) AudioStream as = new AudioStream(in); //和读取文件类似的原理,经翻译之后才播放出来 AudioPlayer.player.start(as); //用静态成员player.start播放音乐 } catch(FileNotFoundException e){ System.out.print("FileNotFoundException "); } catch(IOException e){ System.out.print("有错误!"); } } i++; j = 0; } } catch (IOException z) { z.printStackTrace(); } } //初始化界面 public void launchFrame(){ xx = new JPanel(); //插入一个面板 String[] hours = new String[24]; //长度为24的数组用于存储小时 for (int i = 0; i < hours.length; i++) { hours[i]=i+""; //循环对hour进行赋值 } ho = new JComboBox(hours); //将hour加入到下拉框中 ho.setSize(50,40); //设置大小好像没用 String[] mins = new String[60]; //同理,这是分钟的地方 for (int i = 0; i < mins.length; i++) { mins[i]=i+""; //分钟赋值 } mi = new JComboBox(mins); //分钟下拉框 mi.setSize(50,40); tjnz = new JButton(); //添加闹钟的按钮,拼音首字母 tjnz.setText("添加到闹钟"); //按钮上显示的文字 tjnz.setSize(100,40); schour = new JButton(); //删除闹钟的按钮 schour.setText("从闹钟中删除"); //按钮上显示的文字 schour.setSize(100,40); /** * 将按钮下拉框啥的加入到面板中 */ xx.add(ho); xx.add(mi); xx.add(tjnz); xx.add(schour); this.add(xx); //将面板加入到this对象中,要不然面板就不显示 tjnz.addActionListener(new ActionListener() { //添加按钮的功能 @Override //重写的标识,务必要会 public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub HOUR = Integer.valueOf(ho.getSelectedIndex()); MIN = Integer.valueOf(mi.getSelectedIndex()); //获取到时分后 writeFile(); //写入txt文件保存为闹钟 readFile(); //再读取,这样才能时时更新面板上的全部闹钟 }}); schour.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub HOUR = Integer.valueOf(ho.getSelectedIndex()); MIN = Integer.valueOf(mi.getSelectedIndex()); shanchuFile(); //这里是删除闹钟的按钮功能 readFile(); }}); this.setTitle("小闹钟"); //设置窗口标题 this.setVisible(true); //设置窗口不隐身 this.setSize(700,500); //设置窗口大小 this.setLocation(500, 250); //设置窗口位置,相对于桌面左上角 this.init(); //调用初始化函数进行初始化 this.alert(); //this.run(); //重复调用run()方法结果是秒针一次走12° this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); //设置窗口叉号的功能,点击就关闭程序 } public static void main(String[] args) { ClockTry c = new ClockTry(); //main方法,必有的成分,创建主类对象, c.launchFrame(); //调用初始化面板的方法,简化了本该在main方法中写的代码 }}