一、Java初体验HelloWorld
1.1 实现步骤
将 Java 代码编写到扩展名为 .java 的文件中。
通过 javac 命令对该 java 文件进行编译。
通过 java 命令对生成的 class 文件进行运行。
1.2 编写源程序
1、使用记事本编写HelloWorld.java 源文件
创建文本文档,命名为HelloWorld,然后把文本文档的扩展名改为.java,这就是一个Java源文件。
2、右键编辑HelloWorld.java 文件,写入如下代码:
public class HelloWorld{
public static void main(String []args){
System.out.println("HelloWorld");
}
}
3、检查无误后,Ctrl+s 保存代码。
1.3 代码解析
public class HelloWorld{}解析:
public 访问控制修饰符,后面课程详解[注意,也可以不加public,如果使用public来修饰类,那么类名必须和源文件名一致。]
class 用来定义类,所有的Java程序都离不开类,所有的代码都需要写在类里面。
HelloWorld 我们自定义的类名,类名要符合标识符规范,后面章节给大家介绍
{ } 代码块,成对出现
public static void main(String[] args) 解析:
在Java中,碰到左花括号,要缩进 tab一下。
固定语法,java程序的执行入口,也叫做main方法
System.out.println(“你好,世界!”); 解析:
调用系统输出流,向控制台打印信息
在一个java源文件中可以声明多个class。但是,只能最多有一个类声明为public的。而且要求声明为public的类的类名必须与源文件名相同。
二、Java程序的运行
2.1 常用的DOS命令
盘符: : 进入某个磁盘空间
dir : 列出当前目录下的文件以及文件夹,dir是directory的缩写
md : 创建目录,md是make directory的缩写
rd : 删除目录,当目录不为空时,无法删除,rd是remove directory的缩写
注: 可以先删除目录下所有文件,再删除目录
cd : 进入指定目录,可以多层嵌套,比如 cd 一级目录/二级目录...,cd是change directory的缩写
cd.. : 退回到上一级目录
cd\: 退回到根目录
del : 删除文件,del是delete的缩写
exit : 退出 dos 命令行
echo javase>1.txt : 创建文件及内容
cls :清屏,cls是clean screen的缩写
DOS快捷键:
← →:移动光标
↑ ↓:调阅历史操作命令
Delete和Backspace:删除字符
注:tab:可以自动补全当前输入的文件夹名字
2.2 编译源程序
有了Java源文件,通过编译器将其编译成JVM可以识别的字节码文件。
在该源文件目录下,通过javac编译工具对HelloWorld.java文件进行编译。
如果程序没有错误,没有任何提示,但在当前目录下会出现一个HelloWorld.class文件,该文件称为字节码文件,也是可以执行的java的程序。
1、打开cmd命令行,快捷键win键+R,输入cmd(command 命令行),回车即可
2、在cmd命令行中使用命令进入源文件所在目录,输入 javac 源文件名.扩展名,比如 javac HelloWorld.java
3、运行成功之后,在源文件目录会多出来一个.class文件,这个文件才是jvm可识别的字节码文件。
修改win10 cmd窗口字符集:
https://blog.csdn.net/tfs411082561/article/details/78416569
2.3 运行字节码
编译生成.class 字节码文件之后,我们就可以让jvm执行字节码文件啦
在cmd窗口输入: java 字节码文件名 (注意不需要写扩展名),只要源程序发生改变,肯定要重新编译再运行。
java命令的作用: 负责运行,会启动jvm,加载运行时所需的类库,并对class文件进行执行.
一个文件要被执行,必须需要一个执行的起始点,这个起始点就是main函数。
2.4 常见错误
1、文件找不到错误。
原因1:文件扩展名问题,请检查文件类型,只有是JAVA文件才可以;后缀名隐藏问题;
原因2:路径错误,一定要在Java源文件所在目录执行编译和运行;
原因3:编译的类和生成的字节码文件名可能不一样,以生成才class文件名为主;
2、编译错误。
原因1:大小写错误;
原因2:字母拼写错误;
原因3:缺失符号或中文符号;
注:修改源代码之后,必须重新编译;
学习编程最容易犯的错是语法错误。Java要求你必须按照语法规则编写代码。如果你的程序违反了语法规则,例如:忘记了分号、大括号、引号,或者拼错了单词,java编译器都会报语法错误。尝试着去看懂编译器报告的错误
信息。
2.5 print() 和 println()
无论是使用println()还是print()都是用来打印输出的,但是println()是换行打印,print是不换行打印。
println 换行打印
print 不换行打印
2.6 转义符
转义符 说 明
\n 用来定义换行
\r 用来定义回车
\t 用来定义水平制表符(相当于按了一下tab
\" 用来在双引号里面定义双引号
\' 用来在双引号里面定义单引号
在Java中,只能使用""来表示字符串,如果想在字符串中使用双引号,必须使用转义字符;但是单引号可以用也可以不用。
\\ 用来表示'\'
在Java中,反斜杠是用来做转义字符串的,那么如果我们想要使用反斜杠呢,也可以使用转义符
System.out.println("张三\t12\t河南省郑州市");
System.out.println("李四\t14\t河南省郑州市");
System.out.print("Hello\n");
System.out.print("qqq\n");
System.out.println("----------------------");
System.out.println("我叫\\李四\\,\'朋友们\'都亲切的叫我\"小李子\"");
2.7 Java注释
什么是注释?
注释就是程序的说明。
注释作用:
提高了代码的阅读性;调试程序的重要方法。
java注释类型:
分为单行注释,多行注释和文档注释。
// 单行注释
/* 多行注释 */
/** 文档注释 */
javadoc命令 用来生成帮助文档的
对于单行和多行注释,被注释的文字,不会被JVM(java虚拟机)解释执行。
多行注释里面不允许有多行注释嵌套。
注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来,再用代码去体现。
2.8 良好的编程风格
正确的注释和注释风格:
使用文档注释来注释整个类或整个方法。
如果注释方法中的某一个步骤,使用单行或多行注释。
正确的缩进和空白:
使用一次tab操作,实现缩进。
运算符两边习惯性各加一个空格。比如:2 + 4 * 5。
块的风格:
Java API 源代码选择了行尾风格
三、Java程序运行原理
3.1 Java程序的运行流程
1、按照代码规范来定义Java源文件
2、Java源文件不能直接运行,需要先编译后运行
3、当我们执行javac...的时候,会调用Java编译器对Java源文件进行编译,生成字节码文件
4、当我们执行java...的时候,会调用jvm运行字节码文件(JVM的三项主要功能)
加载代码:由类加载器(class loader)完成;
校验代码:由字节码校验器(bytecode verifier)完成;
执行代码:由运行时解释器(runtime interpreter)完成
javac和java对于代码的校验-注:
javac命令简单来说:可以对我们的语法进行校验,只要语法没有问题,就会生成字节码文件(编译时异常)。
java命令简单来说:校验字节码,判断字节码是否符合代码规范或语言特性(运行时异常)。
3.2 Java两大核心机制
Java虚拟机(Java Virtual Machine)
JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域。负责执行指令,管理数据、内存、寄存器。
对于不同的平台,有不同的虚拟机。只有某平台提供了对应的Java虚拟机,java程序才可在此平台运行。
Java虚拟机机制屏蔽了底层运行平台的差别,实现了“一次编译,随处运行”。
垃圾收集机制(Garbage collection)
不再使用的内存空间应回收——垃圾收集
Java语言相对于C/C++而言消除了程序员回收无用内存空间的责任;提供了一种系统线程跟踪存储空间的分配情况。并在JVM的空闲时,检查并释放那些可被释放的存储器空间。
垃圾收集在Java程序运行过程中自动进行,程序员无法精确控制而后干预。
基本上所有的编程语言都应该回收无用内存,不然就会宕机。
宕机是计算机术语,口语里面我们简单的把停掉机器叫做down机,转换为汉字是“宕机”,但很多人都叫做“当机”/“死机”,虽然不规范但却流行。
宕机,指操作系统无法从一个严重系统错误中恢复过来,或系统硬件层面出问题,以致系统长时间无响应,而不得不重新启动计算机的现象。它属于电脑运作的一种正常现象,任何电脑都会出现这种情况。
3.3 垃圾回收机制-Java与C/C++
一、谁在做 Garbage Collection?
一种流行的说法:在C++里,是系统在做垃圾回收;而在Java里,是Java自身在做。
在C++里,释放内存是手动处理的,要用delete运算符来释放分配的内存。这是流行的说法。确切地说,是应用认为不需要某实体时,就需用 delete告诉系统,可以回收这块空间了。这个要求,对编码者来说,是件很麻烦、很难做到的事。随便上哪个BBS,在C/C++版块里总是有一大堆关于 内存泄漏的话题。
Java采用一种不同的,很方便的方法:Garbage Collection。垃圾回收机制放在JVM里。JVM完全负责垃圾回收事宜,应用只在需要时申请空间,而在抛弃对象时不必关心空间回收问题。
二、对象在啥时被丢弃?
在C++里,当对象离开其作用域时,该对象即被应用抛弃。是对象的生命期不再与其作用域有关,而仅仅与引用有关。Java的垃圾回收机制一般包含近十种算法。对这些算法中的多数,我们不必予以关心。只有其中最简单的一个:引用计数法,与编码有关。一个对象,可以有一个或多个引用变量指向它。当一个对象不再有任何一个引用变量指向它时,这个对象就被应用抛弃了。或者说,这个对象可以被垃圾回收机制回收了。这就是说,当不存在对某对象的任何引用时,就意味着,应用告诉JVM:我不要这个对象,你可以回收了。JVM的垃圾回收机制对堆空间做实时检测。当发现某对象的引用计数为0时,就将该对象列入待回收列表中。但是,并不是马上予以销毁。
三、丢弃就被回收?
该对象被认定为没有存在的必要了,那么它所占用的内存就可以被释放。被回收的内存可以用于后续的再分配。但是,并不是对象被抛弃后当即被回收的。JVM进程做空间回收有较大的系统开销。如果每当某应用进程丢弃一个对象,就立即回收它的空间,势必会使整个系统的运转效率非常低下。
前面说过,JVM的垃圾回收机制有多个算法。除了引用计数法是用来判断对象是否已被抛弃外,其它算法是用来确定何时及如何做回收。JVM的垃圾回收机制要在时间和空间之间做个平衡。因此,为了提高系统效率,垃圾回收器通常只在满足两个条件时才运行:即有对象要回收且系统需要回收。切记垃圾回收要占用时间,因此,Java运行时系统只在需要的时候才使用它。因此你无法知道垃圾回收发生的精确时间。
注:丢弃只是代表我们不在使用该对象,可以被回收了。它不是立马被回收,而是先加入回收列表,等JVM空闲的时候才去进行回收。
四、没有引用变量指向的对象有用吗?
前面说了,没挂上引用变量的对象是被应用丢弃的,这意味着,它在堆空间里是个垃圾,随时可能被JVM回收。不过,这里有个不是例外的例外。对于一次性使用的对象(有些书称之为临时对象),可以不用引用变量指向它。举个最简单也最常见的例子:
System.out.println(“I am Java!”);
就是创建了一个字符串对象后,直接传递给println()方法。
五、应用能干预垃圾回收吗?
许多人对Java的垃圾回收不放心,希望在应用代码里控制JVM的垃圾回收运作。这是不可能的事。对垃圾回收机制来说,应用只有两个途径发消息给 JVM.第一个前面已经说了,就是将指向某对象的所有引用变量全部移走。这就相当于向JVM发了一个消息:这个对象不要了。第二个是调用库方法 System.gc(),多数书里说调用它让Java做垃圾回收。第一个是一个告知,而调用System.gc()也仅仅是一个请求。JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。希望JVM及时回收垃圾,是一种需求。其实,还有相反的一种需要:在某段时间内最好不要回收垃圾。要求运行速度最快的实时系统,特别是嵌入式系统,往往希望如此。
Java的垃圾回收机制是为所有Java应用进程服务的,而不是为某个特定的进程服务的。因此,任何一个进程都不能命令垃圾回收机制做什么、怎么做或做多少。
六、对象被回收时要做的事
一个对象在运行时,可能会有一些东西与其关连。因此,当对象即将被销毁时,有时需要做一些善后工作。可以把这些操作写在finalize()方法(常称之为终止器)里。
protected void finalize(){
// finalization code here
}
这个终止器的用途类似于C++里的析构函数,而且都是自动调用的。但是,两者的调用时机不一样,使两者的表现行为有重大区别。C++的析构函数总是当对 象离开作用域时被调用。这就是说,C++析构函数的调用时机是确定的,且是可被应用判知的。但是,Java终止器却是在对象被销毁时。由上所知,被丢弃的 对象何时被销毁,应用是无法获知的。而且,对于大多数场合,被丢弃对象在应用终止后仍未销毁。
在编码时,考虑到这一点。譬如,某对象在 运作时打开了某个文件,在对象被丢弃时不关闭它,而是把文件关闭语句写在终止器里。这样做对文件操作会造成问题。如果文件是独占打开的,则其它对象将无法 访问这个文件。如果文件是共享打开的,则另一访问该文件的对象直至应用终结仍不能读到被丢弃对象写入该文件的新内容。
至少对于文件操作,编码者应认清Java终止器与C++析构函数之间的差异。
那么,当应用终止,会不会执行应用中的所有finalize()呢?据Bruce Eckel在Thinking in Java里的观点:“到程序结束的时候,并非所有收尾模块都会得到调用”。这还仅仅是指应用正常终止的场合,非正常终止呢?
因此,哪些收尾操作可以放在finalize()里,是需要酌酎的。