最后有彩蛋哈哈哈哈哈哈哈-----------------------------
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。
Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性等特点 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等—来自百度百科的解释
JavaSE:标准版(桌面程序,控制台开发…)
JavaME:嵌入式开发(手机,小家电…)
JavaEE:E企业级开发(Web端,服务器开发…) 现在最常用的版本
JDK(Java Development kit): 指的是Java开发工具集。JDK是整个Java得核心,包括了Java基础类库、Java运行环境(jre)和Java开发工具。
JRE(Java Runtime Environment):指得是Java运行时的环境。Java程序运行的时候必须要JRE的支持,如果只安装JRE的话,那么这个系统可以跑任何的Java程序,但是不可以开发Java程序。
JVM(Java Virtual Machine):指得是Java虚拟机,它是Java可跨平台运行的核心,所有的Java程序首先被编译成.class文件,它能够将class文件中的字节码指令进行识别并调用操作系统上的API完成工作,从而与操作系统进行交互,只有JVM还不能将class执行,因为在解释class的时候Jvm需要调用解释所需要的类库lib,而Jre包含了lib类库,Jvm屏蔽了具体操作系统的相关信息,使得Java程序只需要生成在java虚拟机上运行的目标代码(字节码),就可以不加修改的在多个平台运行。
https://www.runoob.com/java/java-environment-setup.html 菜鸟教程或百度搜索
4.2.1、随便新建一个文件夹,存放代码
4.2.2、新建一个Java文件,文件后缀名为 .java
4.2.3、编写代码
public class Hello{
public static void main(String[] args){
System.out.print("Hello,World!");
}
}
4.2.4、通过doc命令进入到新建的Java文件目录,使用javac java文件名 编译出一个 .class文件
4.2.5、在doc命令中输入java java class文件名 ,来运行java程序
单行注释、多行注释、文档注释
public static void main(String[] args) {
//单行注释 可以注释一行文字
//输出一个Hello,World!
System.out.println("Hello,World!");
//多行注释 可以注释一段文字 /* */
/*
输出一个Hello,World!
输出一个Hello,World!
输出一个Hello,World!
输出一个Hello,World!
输出一个Hello,World!
*/
//JavaDoc 文档注释 /** */
/**
* @Description HelloWorld
* @Author leoyan
* */
}
Java 所有组成的部分都需要名字、类名、变量名、以及方法名都称为标识符。
注意点
关键字 | 含义 |
---|---|
abstract | 表明类或者成员方法具有抽象属性 |
assert | 断言,用来进行程序调试 |
boolean | 基本数据类型之一,声明布尔类型的关键字 |
break | 提前跳出一个块 |
byte | 基本数据类型之一,字节类型 |
case | 用在switch语句之中,表示其中的一个分支 |
catch | 用在异常处理中,用来捕捉异常 |
char | 基本数据类型之一,字符类型 |
class | 声明一个类 |
const | 保留关键字,没有具体含义 |
continue | 回到一个块的开始处 |
default | 默认,例如,用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现 |
do | 用在do-while循环结构中 |
double | 基本数据类型之一,双精度浮点数类型 |
else | 用在条件语句中,表明当条件不成立时的分支 |
enum | 枚举 |
extends | 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口 |
final | 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量 |
finally | 用于处理异常情况,用来声明一个基本肯定会被执行到的语句块 |
float | 基本数据类型之一,单精度浮点数类型 |
for | 一种循环结构的引导词 |
goto | 保留关键字,没有具体含义 |
if | 条件语句的引导词 |
implements | 表明一个类实现了给定的接口 |
import | 表明要访问指定的类或包 |
instanceof | 用来测试一个对象是否是指定类型的实例对象 |
int | 基本数据类型之一,整数类型 |
interface | 接口 |
long | 基本数据类型之一,长整数类型 |
native | 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的 |
new | 用来创建新实例对象 |
package | 包 |
private | 一种访问控制方式:私用模式 |
protected | 一种访问控制方式:保护模式 |
public | 一种访问控制方式:共用模式 |
return | 从成员方法中返回数据 |
short | 基本数据类型之一,短整数类型 |
static | 表明具有静态属性 |
strictfp | 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范 |
super | 表明当前对象的父类型的引用或者父类型的构造方法 |
switch | 分支语句结构的引导词 |
synchronized | 表明一段代码需要同步执行 |
this | 指向当前实例对象的引用 |
throw | 抛出一个异常 |
throws | 声明在当前定义的成员方法中所有需要抛出的异常 |
transient | 声明不用序列化的成员域 |
try | 尝试一个可能抛出异常的程序块 |
void | 声明当前成员方法没有返回值 |
volatile | 表明两个或者多个变量必须同步地发生变化 |
while | 用在循环结构中 |
关键字一律用小写字母标识,按其用途划分为如下几组。
用于数据类型。 用于数据类型的关键字有 boolean、byte、char、 double、 false、float、int、long、new、short、true、void、instanceof。
用于语句。 用于语句的关键字有break、case、 catch、 continue、 default 、do、 else、 for、 if、return、switch、try、 while、 finally、 throw、this、 super。
用于修饰 用于修饰的关键字有 abstract、final、native、private、 protected、public、static、synchronized、transient、 volatile。
用于方法、类、接口、包和异常。 用于方法、类、接口、包和异常的关键字有 class、 extends、 implements、interface、 package、import、throws。
还有些关键字如cat、 future、 generic、innerr、 operator、 outer、rest、var等都是Java保留的没有意义的关键字。
Java还有3个保留字:true、false、null。它们不是关键字,而是文字。包含Java定义的值。和关键字一样,它们也不可以作为标识符使用。
直接看菜鸟教程–https://www.runoob.com/java/java-basic-datatypes.html
基础类型和引用类型 扩展 字节 和 进制
数据类型拓展:
计算时float 是有限的离散的 舍入误差 大约 接近单不等于
转义字符
字符计算 字母和中文
java是强类型语言,所有需要进行运算的时候都需要进行类型转换。
低-------------------------------------> 高
byte,short,char->int->long->float->double
运算中,不同类型的数据先转换成同一类型,然后在进行计算。
强制转换
自动转换
注意
1、不能对布尔类型进行转换。
2、不能把对象类型转换成不相干类型
3、在把高容量转为低容量的时候,强制转换,转换的时候可能存在内存溢出,或者是精度问题。
变量
int num = 10;//数据类型 变量名 = 值
变量作用域
public class Demo01{
//在main方法中
public static void main (String[] args){
//局部变量:必须声明和初始化值
int i = 10;
System.out.println(i);
}
}
public class Demo02{
//实例变量:从属于对象;如果不自行初始化,这个类型的默认值0 , 0.0
//布尔值:默认是false
//除了基本类型,其余的默认值都是null;
String name;
int age;
public static void main (String[] args){
//格式:变量类型 变量名字 = new Demo02();
Demo02 demo02 = new Demo02();
System.out.println( demo02.age );//0
System.out.println( demo02.name );//null
}
}
public class Demo03{
//类变量 static 从属于Demo03这个类,一起出来,一起消失的
//使用static关键字,可以直接调用
static double salary = 2500;
public static void main (String[] args){
System.out.println( salary );
}
}
常量
public class Demo04{
//一般使用final关键字来表示
//修饰符(static final....),不存在先后顺序
// final static double pi=3.14;
//static final静态的常量,始终不会改变
static final double PI = 3.14;
public static void main (String[] args){
System.out.println( PI);
}
}
变量的命名规范
来自菜鸟教程–https://www.runoob.com/java/java-operators.html?_t_t_t=0.24160324046213755
计算机的最基本用途之一就是执行数学运算,作为一门计算机语言,Java也提供了一套丰富的运算符来操纵变量。我们可以把运算符分成以下几组:
操作符 | 描述 |
---|---|
+ | 加法 - 相加运算符两侧的值 |
- | 减法 - 左操作数减去右操作数 |
* | 乘法 - 相乘操作符两侧的值 |
/ | 除法 - 左操作数除以右操作数 |
% | 取余 - 左操作数除以右操作数的余数 |
++ | 自增: 操作数的值增加1 |
– | 自减: 操作数的值减少1 |
运算符 | 描述 | 例子 |
---|---|---|
== | 检查如果两个操作数的值是否相等,如果相等则条件为真。 | (A == B)为假。 |
!= | 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 | (A != B) 为真。 |
> | 检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 | (A> B)为假。 |
< | 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 | (A |
>= | 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 | (A> = B)为假。 |
<= | 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 | (A <= B)为真。 |
操作符 | 描述 | 例子 |
---|---|---|
& | 如果相对应位都是1,则结果为1,否则为0 | (A&B),得到12,即0000 1100 |
| | 如果相对应位都是 0,则结果为 0,否则为 1 | (A | B)得到61,即 0011 1101 |
^ | 如果相对应位值相同,则结果为0,否则为1 | (A ^ B)得到49,即 0011 0001 |
〜 | 按位取反运算符翻转操作数的每一位,即0变成1,1变成0。 | (〜A)得到-61,即1100 0011 |
<< | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240,即 1111 0000 |
>> | 按位右移运算符。左操作数按位右移右操作数指定的位数。 | A >> 2得到15即 1111 |
>>> | 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 | A>>>2得到15即0000 1111 |
操作符 | 描述 | 例子 |
---|---|---|
&& | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | (A && B)为假。 |
| | | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | (A | | B)为真。 |
! | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 | !(A && B)为真。 |
操作符 | 描述 | 例子 |
---|---|---|
= | 简单的赋值运算符,将右操作数的值赋给左侧操作数 | C = A + B将把A + B得到的值赋给C |
+ = | 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 | C + = A等价于C = C + A |
- = | 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 | C - = A等价于C = C - A |
* = | 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 | C * = A等价于C = C * A |
/ = | 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 | C / = A,C 与 A 同类型时等价于 C = C / A |
(%)= | 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 | C%= A等价于C = C%A |
<< = | 左移位赋值运算符 | C << = 2等价于C = C << 2 |
>> = | 右移位赋值运算符 | C >> = 2等价于C = C >> 2 |
&= | 按位与赋值运算符 | C&= 2等价于C = C&2 |
^ = | 按位异或赋值操作符 | C ^ = 2等价于C = C ^ 2 |
| = | 按位或赋值操作符 | C | = 2等价于C = C | 2 |
条件运算符
条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量。
int a , b;
a = 10;
// 如果 a 等于 1 成立,则设置 b 为 20,否则为 30
b = (a == 1) ? 20 : 30;
结果 30
来自博客:https://blog.csdn.net/qq_37829947/article/details/107294759
包机制
为了更好的组织类,Java提供了包机制,用于区别类名的命名空间。
包语句的语法格式为:
package pkg1[.pkg2[.pkg3...]];
一般利用公司域名倒置作为包名;
为了能够使用某一个包的成员,需要在Java程序中明确导入该包。使用“import”语句可完成此功能。
import package1[.package2...].(classname|\*);
JavaDoc
JavaDoc命令是用来生成自己API文档的。
参数信息:
/**
* @author XXXX
* @version 1.0
* @since 1.8
*/
public class Doc {
String name;
/**
* @author XXXX
* @param name
* @return
* @throws Exception
*/
public String test(String name) throws Exception{
return name;
}
}
Idea生成JavaDoc文档:
点击目录下的index.html产看生成的文档
java.util.Scanner是java5的新特性,我们可以通过Scanner类来获取用户的输入
基本语法:
Scanner s = new Scanner(System.in);
通过Scanner 类的next()与nextLine()方法获取输入的字符串,在读取之前我们需要使用hasNext()和hasNextLine()判断是否还有输入数据;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("使用Scanner接受:");
//判断用户有没有输入字符串
//scanner.hasNext()
//scanner.hasNextLine()
if (scanner.hasNextLine()){
//使用next接受
//String str = scanner.next();
//使用nextLine接受
String str = scanner.nextLine();
System.out.println("输出内容为:"+str);
}
//凡是使用io操作,使用完后不关闭会浪费资源。
scanner.close();
}
next():
1、一定要读取到有效的字符后才可以结束输入;
2、对输入有效字符串遇到空白的,next()方法会自动将其去掉;
3、只有输入有效字符串后才将其后面输入的空白做为分隔符或者结束符;
4、next()不能得到带有空格的字符串;
nextLine():
1、以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符;
2、可以获取空白;
Scanner还有很多扩充的方法,可百度学习;
2.1、Java的基本结构就是顺序结构,除非特别指明,否则按照顺序一步一步执行。
2.2、循序结构是最简单的算法结构。
2.3、语句与语句之间,框与框之间是按照从上到下的顺序进行的,它是有若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的基本算法结构。
很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用if语句来表达
语法:
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}
当需求中需要两个判断,也就是需要一个双选择结构,所以就有了if-else结构。
语法:
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}else{
//如果布尔表达式为false将执行的语句
}
很多选择不仅仅只有两个,所以要用多选择结构处理
语法:
if(布尔表达式1){
//如果布尔表达式1为true将执行的语句
}else if(布尔表达式2){
//如果布尔表达式2为true将执行的语句
}else if(布尔表达式3){
//如果布尔表达式3为true将执行的语句
}else{
//如果以上布尔表达式都不为true将执行的语句
}
在一个if里再加一个if
语法:
if(布尔表达式1){
//如果布尔表达式1为true将执行的语句
if(布尔表达式2){
//如果布尔表达式2的值为true执行的语句
}
}
switch case语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
switch语句重点变量类型可以是:
语法:
int N = 2;
switch (N){
case 2:
System.out.println("2");//语句
break;//可选
case 's':
System.out.println("s");
break;
//可以有任意数量的case语句
default://可选
System.out.println("wrong");
}
case后面的表示前面switch后面的变量对应的值,下面是值相对应就输出的语句。
break这里的作用就是切断语句,如果中间没有break,那么就会发生穿透,也就是在对应值的case后面的语句都执行。
default指以上case都不符合的情况下,就输出default下的语句。
注意这里char的话是单引号,且下面case后的也要写单引号才对应。case后面也可以用string类型。
while循环是最基本的循环
while(布尔表达式){
//循环内容
}
只要布尔表达式为true,循环就会继续
我们大多数情况是会让循环停止下来的,我们需要一个让表达是失效的方式来结束循环。
少部分循环需要循环一直执行,比如服务器请求响应监听等。(我们用while(true)这种方式让他一直执行,进入死循环)
循环条件一直为true会造成无限循环,我们正常的业务编程中应该尽量避免死循环,它会影响程序性能或者程序卡死崩溃。
对于while语句,如果不满足条件,则不进入循环,但有时需要即使不满足条件也要至少执行一次。
do-while就是至少会执行一次的循环
do{
//代码语句
}while(布尔表达式)
while 和do-while的区别
for循环语句是支持迭代的一种通用结构,是最有效,最灵活的循环结构。
for循环执行的次数实在执行前就确定的,语法:
for(初始化;布尔表达式;更新){
//代码语句
}
//for的死循环
for(; ;){
}
for循环的说明
最先执行初始化步骤,可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
然后检测布尔表达式的值,如果为true,循环体被执行,如果为false,循环终止。开始执行循环体后面的语句。
执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)。
再次检测布尔表达式,循环执行上面过程。
public static void main(String[] args) {
//计算0-100之间奇数和偶数的和;
int oddSum=0;
int eveSum=0;
for (int i = 0; i <= 100; i++) {
if (i%2!=0){
//不能整除2的是奇数
oddSum+=i;
}else{
eveSum+=i;
}
}
System.out.println("奇数的和:"+oddSum);
System.out.println("偶数的和:"+eveSum);
}
public static void main(String[] args) {
//输出1-1000能被5整除的数,并且每行输出3个
for (int i = 1; i <= 1000; i++) {
if (i%5==0){
System.out.print(i+"\t");
}
if (i%(5*3)==0){
//每行3个然后换行
System.out.println();
}
}
}
public static void main(String[] args) {
//输出9*9乘法表
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(i+"*"+j+"="+(j*i) + "\t");
}
System.out.println("\n");
}
}
它是Java5引用的一种主要用于数组或者集合的增强型for循环
语法:
for(声明语句:表达式)
{
//代码句子
}
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者是返回值为数组的方法
举例:
public static void main(String[] args) {
int[] numbers ={
10,20,30,40,50};
for(int x:numbers){
System.out.println(x);
}
}
其实就是遍历了一遍数组内的数,与之相对应的普通for循环语句是:
public static void main(String[] args) {
int[] numbers ={
10,20,30,40,50};//定义了一个数组
for (int i = 0; i < 5; i++) {
System.out.println(numbers[i]);
}
}
这里也是遍历了一遍数组,在这个普通的for循环中,从0开始,i<5也意味着语句输出5次。
break在任何循环语局的主体部分,据可用break控制循环的流程,break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
continue语句用作循环语句体中,用于种植某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
public static void main(String[] args) {
int i = 0;
while(i<100){
i++;
if(i%10 == 0){
System.out.println();
continue;
}
System.out.print(i+"\t");
}
}
这里通过continue来实现将10的倍数跳过并换行
Java方法是语句的集合,它们在一起执行一个功能。
设计方法的原则:方法的本意是功能块,就是实现某个功能的语句模块。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样利于后期扩展。
方法的优点
方法的命名规则
一般情况下,定义一个方法包含以下语法:
修饰符 返回值类型 方法名(参数类型 参数名){ … 方法体 … return 返回值; }
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
返回值类型 :方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
方法体:方法体包含具体的语句,定义该方法的功能。
方法调用
Java 支持两种调用方法的方式,根据方法是否返回值来选择。
当程序调用一个方法时,程序的控制权交给了被调用的方法。当被调用方法的返回语句执行或者到达方法体闭括号时候交还控制权给程序。
当方法返回一个值的时候,方法调用通常被当做一个值。例如:
int larger = max(30, 40);
如果方法返回值是void,方法调用一定是一条语句。例如,方法println返回void。下面的调用是个语句:
System.out.println(“Hello,world”);
Java是通过值传递参数的!
重载就是在一个类中,有相同的函数名,但形参不同的函数。
方法重载的规则:
在 Java 5 中提供了变长参数,允许在调用方法时传入不定长度的参数。变长参数是 Java 的一个语法糖,本质上还是基于数组的实现,在定义方法时,在最后一个形参后加上三点(…),就表示该形参可以接受多个参数值,多个参数值被当成数组传入。上述定义有几个要点需要注意:
可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数;
由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数;
Java的可变参数,会被编译器转型为一个数组
变长参数在编译为字节码后,在方法签名中就是以数组形态出现的。这两个方法的签名是一致的,不能作为方法的重载。如果同时出现,是不能编译通过的。可变参数可以兼容数组,反之则不成立
public void foo(String...varargs){}
foo("arg1", "arg2", "arg3");
//上述过程和下面的调用是等价的
foo(new String[]{"arg1", "arg2", "arg3"});
递归就是一个程序或函数在其中定义或说明有之间或者间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个原问题相似的规模较小的问题来求解,递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算,大大的减少了程序的代码量,递归的能力在于用有限的语句来定义对象的无限集合,一般来说,递归需要边界条件,递归前进段和递归返回段,当边界条件不满足时,递归前进,当边界条件满足时,递归返回。
说白了就是方法自己调用自己。
递归结构包含两部分:
递归头:什么时候不调用自己的方法。如果没有头,将陷入死循环。
递归体:什么时候需要调用自己的方法。
public static void main(String[] args) {
//递归阶乘
System.out.println(f(100));
}
public static int f(int n) {
if (n == 1) {
return 1;
} else {
return n * f(n - 1);
}
}
附上一个大佬讲解递归的博客
数组是相同类型数据的有序集合;
数组描述的是相同类型的若干数据,按照一定的先后次序排列组合而成;
每一个数据称为一个数组元素,每个数组元素可通过下标来访问他们,数组的下标索引是从0开始的;
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; // 首选的方法
或
dataType arrayRefVar[]; // 效果相同,但不是首选方法
创建数组
Java语言使用new操作符来创建数组,语法如下:
arrayRefVar = new dataType[arraySize];
上面的语法语句做了两件事:
使用 dataType[arraySize] 创建了一个数组。
把新创建的数组的引用赋值给变量 arrayRefVar。
数组变量的声明,和创建数组可以用一条语句完成,如下所示:
dataType[] arrayRefVar = new dataType[arraySize];
另外,你还可以使用如下的方式创建数组。
dataType[] arrayRefVar = {value0, value1, ..., valuek};
数组的元素是通过索引访问的。数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1。
public static void main(String[] args) {
// 数组大小
int size = 10;
// 定义数组
double[] myList = new double[size];
myList[0] = 5.6;
myList[1] = 4.5;
myList[2] = 3.3;
myList[3] = 13.2;
myList[4] = 4.0;
myList[5] = 34.33;
myList[6] = 34.0;
myList[7] = 45.45;
myList[8] = 99.993;
myList[9] = 11123;
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < size; i++) {
total += myList[i];
}
System.out.println("总和为: " + total);
}
数组创建时内存分析:
数组的默认初始化:
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间(在堆中初始化大小了),其中每个元素也按照实例变量同样的方式被隐式初始化了;
数组的特点:
数组的长度是确定的,数组一旦被创建,它的大小就不可以被改变。
其元素必须是相同类型,不允许出现混合类型。
数组中定义的元素类型可以是任何类型,包括基本类型和引用类型。
数组属于引用类型,数组也可以被看作是对象。数组中每个元素相当于对象中的成员变量,数组本身就是对象,Java中对象在堆中,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
public static void main(String[] args) {
double[] myList = {
1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (int i = 0; i < myList.length; i++) {
System.out.println(myList[i] + " ");
}
// 计算所有元素的总和
double total = 0;
for (int i = 0; i < myList.length; i++) {
total += myList[i];
}
System.out.println("Total is " + total);
// 查找最大元素
double max = myList[0];
for (int i = 1; i < myList.length; i++) {
if (myList[i] > max) max = myList[i];
}
System.out.println("Max is " + max);
}
使用for-each
public static void main(String[] args) {
double[] myList = {
1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: myList) {
System.out.println(element);
}
}
反转数组:
public static void main(String[] args) {
int[] list={
1,2,3,4,5};
System.out.println(Arrays.toString(reverse(list)));
}
public static int[] reverse(int[] list) {
int[] result = new int[list.length];
for (int i = 0, j = result.length - 1; i < list.length; i++, j--) {
result[j] = list[i];
}
return result;
}
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组;
多维数组的动态初始化(以二维数组为例)
直接为每一维分配空间,格式如下:
type[][] typeName = new type[typeLength1][typeLength2];
type 可以为基本数据类型和复合数据类型,arraylength1 和 arraylength2 必须为正整数,arraylength1 为行数,arraylength2 为列数。
例如:
int a[][] = new int[2][3];
解析:
二维数组 a 可以看成一个两行三列的数组。
解析多维数组
public static void main(String[] args) {
//这就相当于 int[][] list = new int[4][2];
int[][] list={
{
1,2},{
2,3},{
3,4},{
4,5}};
for (int i = 0; i <list.length ; i++) {
for (int j = 0; j <list[j].length ; j++) {
System.out.println(list[i][j]);
}
}
}
java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。
具有以下功能:
给数组赋值:通过 fill 方法。
对数组排序:通过 sort 方法,按升序。
比较数组:通过 equals 方法比较数组中元素值是否相等。
查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
等等还有很多方法。
依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。
实现思路:
两层循环,外层循环轮数,内循环比较大小。
用二重循环实现,外循环变量设为i,内循环变量设为j。假如有n个数需要进行排序,则外循环重复n-1次,内循环依次重复n-1,n-2,…,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,…,n-1,对于每一个i,j的值依次为0,1,2,…n-i 。
public static void main(String[] args) {
int[] array = {
2, 5, 11, 66, 34, 3456, 3452, 6753, 234, 1};
System.out.print(Arrays.toString(sort(array)));
}
/**
* 冒泡排序步骤
* 1、比较数组中相邻的两元素,如果第一个比第二个大,交换他们位置
* 2、每次比较都会产生一个最大或最小数字
* 3、下一轮比较时可以少比较一次
* 4、依次循环指到结束
*/
public static int[] sort(int[] array) {
int temp = 0;
for (int i = 0; i < array.length - 1; i++) {
boolean flag = false; //通过flag减少没有意义的比较
for (int j = 0; j < array.length - 1 - i; j++) {
//如果前一个数比后一个大 结果 [1, 2, 5, 11, 34, 66, 234, 3452, 3456, 6753] 正序
//如果前一个数比后一个小 结果 [6753, 3456, 3452, 234, 66, 34, 11, 5, 2, 1] 倒序
if (array[j + 1] > array[j]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
flag = true;
}
}
if (flag == false) {
break;
}
}
return array;
}
当一个数组中大部分元素为0,或者同一值的数组时,可以使用稀疏数组来保存改数组;
稀疏数组的处理方式为:
记录数据中有几行几列,有多少不同值
把具有不同值的元素和行列及值记录在一个小规模数组中,从而缩小程序规模;
解析:[0] 6行7列 意思就是在这个数据有多几行几列,值就是在这个数据中的有少数字总数;
解析:[1] 第0行第三列 有一个值为22…
应用实例
1)使用稀疏数组,来保留类似前面的二维数组(棋盘、地图等等)
2)把稀疏数组存盘,并且可以从新恢复原来的二维数组数
代码示例:
public static void main(String[] args) {
// 创建一个原始的二维数组 11 * 11
// 0: 表示没有棋子, 1 表示 黑子 2 表蓝子
int chessArr1[][] = new int[11][11];
chessArr1[1][2] = 1;
chessArr1[2][3] = 2;
// 输出原始的二维数组
System.out.println("原始的二维数组~~");
for (int[] row : chessArr1) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
// 将二维数组 转 稀疏数组的思
// 1. 先遍历二维数组 得到非0数据的个数
int sum = 0;
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (chessArr1[i][j] != 0) {
sum++;
}
}
}
// 2. 创建对应的稀疏数组
int sparseArr[][] = new int[sum + 1][3];
// 给稀疏数组赋值
sparseArr[0][0] = 11;
sparseArr[0][1] = 11;
sparseArr[0][2] = sum;
// 遍历二维数组,将非0的值存放到 sparseArr中
int count = 0; //count 用于记录是第几个非0数据
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 11; j++) {
if (chessArr1[i][j] != 0) {
count++;
sparseArr[count][0] = i;
sparseArr[count][1] = j;
sparseArr[count][2] = chessArr1[i][j];
}
}
}
// 输出稀疏数组的形式
System.out.println();
System.out.println("得到稀疏数组为~~~~");
for (int i = 0; i < sparseArr.length; i++) {
System.out.printf("%d\t%d\t%d\t\n", sparseArr[i][0], sparseArr[i][1], sparseArr[i][2]);
}
System.out.println();
//将稀疏数组 --》 恢复成 原始的二维数组
/*
* 1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组,比如上面的 chessArr2 = int [11][11]
2. 在读取稀疏数组后几行的数据,并赋给 原始的二维数组 即可.
*/
//1. 先读取稀疏数组的第一行,根据第一行的数据,创建原始的二维数组
int chessArr2[][] = new int[sparseArr[0][0]][sparseArr[0][1]];
//2. 在读取稀疏数组后几行的数据(从第二行开始),并赋给 原始的二维数组 即可
for (int i = 1; i < sparseArr.length; i++) {
chessArr2[sparseArr[i][0]][sparseArr[i][1]] = sparseArr[i][2];
}
// 输出恢复后的二维数组
System.out.println();
System.out.println("恢复后的二维数组");
for (int[] row : chessArr2) {
for (int data : row) {
System.out.printf("%d\t", data);
}
System.out.println();
}
}
面向对象(Object Oriented)是一种新兴的程序设计方法,或者是一种新的程序设计规范(paradigm),其基本思想是使用对象、类、继承、封装、多态等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。
面向对象的本质:以类的方式组织代码,以对象的方式组织(封装)数据
面向对象的核心思想:抽象
面向对象的的三大特征:封装、多态、继承
在面向对象之前都是面向过程编程方式;
面向过程思想:
步骤清晰简单,第一步做什么,第二步做什么。。。。
面向过程适合处理一些简单的问题
面向对象思想:
物以类聚,分类的思维模式,思考问题首先会解决问题需要那些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的探索。
面向对象适合处理复杂的问题,适合处理多人协作的问题
对于描述复杂的事物,为了宏观上的把握,从整体合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍需要面向过程去处理;
https://blog.csdn.net/plus_left/article/details/83663041
在程序运行的时候static 静态方法就已经被创建了,而静态方法是在类实例化的时候创建。
对象的本质就是值传递。
对象是具体的事物,类是对对象的抽象描述。
类是一个的模板。抽象,对象是一个具体的实例。
使用new关键字创建对象
Object obj = new Object();
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及类的构造器的调用。
构造器
类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
必须和类名相同
必须没有返回类型,也不能写void
构造器的作用就是实例化初始值;
在使用new关键字的时候,本质就是调用了无参构造器;有参构造,一旦定义了有参构造,无参构造必须显示定义;
public class Student{
String name;
public Student(){
}//无参构造
public Student(String name){
this.name = name;
}//有参构造
}
对象创建内存分析
public class Test{
public static void main(String[] args){
Pet dog = new Pet();
dog.name = "duoduo";
dog.age=1;
dog.shout();
Pet cat = new Pet();
cat.name="mimi";
cat.age=1;
cat.shout();
}
}
//创建一个类
public class Pet{
public String name;
public int age;
public void shout(){
System.out.print("叫了一声");
}
}
在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。
封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。
要访问该类的代码和数据,必须通过严格的接口控制。
封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。
适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。
封装的优点
良好的封装能够减少耦合。
类内部的结构可以自由修改。
可以对成员变量进行更精确的控制。
隐藏信息,实现细节。
该露的露,该藏的藏:程序设计追求”高内聚,低耦合“。高内聚就是类的内部数据细节自己操作完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用;
**属性私有,get/set **,在set值得时候,可以在类中对应的方法加条件判断,比如一些值范围等…
public class Student{
private int age;
//采用 this 关键字是为了解决实例变量(private int age)和局部变量(setAge(int age)中的age变量)之间发生的同名的冲突。
public void setAge(int age){
if(age > 100 || age < 0){
this.age = age;
}else{
this.age = 60;
}
}
}
在Java中所有类,都默认直接或间接继承了Object类。
在 Java 中通过 extends 关键字可以申明一个类是从另外一个类继承而来的,一般形式如下:
类的继承格式:class 父类 { } class 子类 extends 父类 { }
切记:java只有单继承,没有多继承。但支持多重继承
继承的特性
super–this
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。(调用父类,继承后在可以用)(父类的构造)
this关键字:指向自己的引用。(调用自己类,没有继承也可以使用)(本类的构造)
super注意:
super调用父类的构造方法必须在子类的构造方法代码的第一行;
super只能出现在子类的方法或者构造方法中;
super和this不能同时调用;
方法的重写
重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!
方法的重写规则
需要有继承关系才能实现方法重写;如果子类重写了父类的方法,调用时就用的是子类中的。
多态是同一个行为具有多个不同表现形式或形态的能力。
多态的优点
多态存在的三个必要条件
父类:
public class Father{
public void run(){
System.out.print("跑");
}
}
子类:
public class Son extent Father{
public void run(){
System.out.print("跑跑");
}
}
main方法:
public static void main(String[] agrs){
//一个对象的实际类型是确定的
//可以指向的引用类型就不确定了,父类的引用类型可以指向子类
Son s1 = new Son(); //可以调用自己的或者继承父类的
Father f1 = new Son(); //可以指向子类,但是不能调用子类的方法。 Father就是引用类型,Son是实际类型
s1.run();
f1.run();
//结果都是跑跑,因为子类继承并实现了父类方法,调用时则使用子类的;
// 对象能执行那些方法主要看左边引用类型的,和右边关系不大!
//多态是方法的多态,属性没有多态!
}
static关键字:
静态方法可不易直接调用非静态方法,非静态方法可以直接调用静态方法,因为静态方法在程序运行的时候已经被初始化!
调用静态方法 类名 . 静态方法名; 非静态的需要将类初始化后在点。
还可以静态导入包:
import static java.lang.Math.random; //不加static是错误的;
public class Test{
{
System.out.print("非静态代码块");
}
static{
System.out.print("静态代码块");
}
public Test(){
System.out.print("构造方法");
}
//加载顺序 静态代码块---非静态代码块---构造方法
}
抽象类必须是使用abstract来修饰的,使用abstract来修饰类就是抽象类,使用abstract来修饰的方法就是抽象方法,抽象类中可以存在抽象方法和非抽象方法,但是普通类中不可以存在抽象方法。抽象类也只能是单继承的!
public abstract class Test{
//这就是一个抽象类
public abstract void hello();//这就是一个抽象方法
}
抽象方法的 3 个特征如下:
注意:在使用 abstract 关键字修饰抽象方法时不能使用 private 修饰,因为抽象方法必须被子类重写,而如果使用了 private 声明,则子类是无法重写的。
抽象类是从多个类中抽象出来的模板,如果将这种抽象进行的更彻底,则可以提炼出一种更加特殊的“抽象类”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解为一种特殊的类,不同的是接口的成员没有执行体,是由全局常量和公共的抽象方法所组成。
Java 接口的定义方式与类基本相同,不过接口定义使用的关键字是 interface,接口定义的语法格式如下:
[public] interface interface_name [extends interface1_name[, interface2_name,…]] {
// 接口体,其中可以包含定义常量和声明方法
[public] [static] [final] type constant_name = value; // 定义常量
[public] [abstract] returnType method_name(parameter_list); // 声明方法
}
/**
public 表示接口的修饰符,当没有修饰符时,则使用默认的修饰符,此时该接口的访问权限仅局限于所属的包;
interface_name 表示接口的名称。接口名应与类名采用相同的命名规则,即如果仅从语法角度来看,接口名只要是合法的标识符即可。如果
要遵守 Java 可读性规范,则接口名应由多个有意义的单词连缀而成,每个单词首字母大写,单词与单词之间无需任何分隔符。
extends 表示接口的继承关系;
interface1_name 表示要继承的接口名称;
constant_name 表示变量名称,一般是 static 和 final 型的;
returnType 表示方法的返回值类型;
parameter_list 表示参数列表,在接口中的方法是没有方法体的。
*/
接口对于其声明、变量和方法都做了许多限制:
内部类就是在一个类的内部在定义一个类,比如A类中定义一个B类,那么对于B来说A就是外部类,对于A来说B就是内部类!
内部类可以分为:局部内部类、静态内部类、成员内部类、匿名内部类;
内部类的特点如下:
内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class
文件,但是前面冠以外部类的类名和$
符号。
内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。
public class Test {
public class InnerClass {
//内部类
public int getSum(int x,int y) {
return x + y;
}
}
public static void main(String[] args) {
Test.InnerClass ti = new Test().new InnerClass(); // Test.innerClass是内部类的完整类名
int i = ti.getSum(2,3);
System.out.println(i); // 输出5
}
}
异常通常指,你的代码可能在编译时没有错误,可是运行时会出现异常。比如常见的空指针异常。也可能是程序可能出现无法预料的异常,比如你要从一个文件读信息,可这个文件不存在,程序无法运行下去了,故程序要抓这些异常,通过异常处理机制来抛出这些异常,程序员就可以通过抛出的异常来修改代码;
Thorwable类(表示可抛出)是所有异常和错误的超类,两个直接子类为Error和Exception,分别表示错误和异常。其中异常类Exception又分为运行时异常(RuntimeException)和非运行时异常, 这两种异常有很大的区别,也称之为不检查异常(Unchecked Exception)和检查异常(Checked Exception)。下面将详细讲述这些异常之间的区别与联系:
1、Error与Exception
Error是程序无法处理的错误,它是由JVM产生和抛出的,比如OutOfMemoryError、ThreadDeath等。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
Exception是程序本身可以处理的异常,这种异常分两大类运行时异常和非运行时异常。程序中应当尽可能去处理这些异常。
2、运行时异常和非运行时异常
运行时异常都是RuntimeException类及其子类异常,如NullPointerException、IndexOutOfBoundsException等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
非运行时异常是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOException、SQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常。
抛出异常
如果一个方法没有捕获到一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法签名的尾部。
也可以使用 throw 关键字抛出一个异常,无论它是新实例化的还是刚捕获到的。
throw常用在方法体内,throws 则用在方法上抛出异常;
public void deposit(double amount) {
// Method implementation
throw new RemoteException();
}
//一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
public void withdraw(double amount) throws RemoteException,
InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
捕获异常
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:
try
{
// 程序代码
}catch(ExceptionName e1)
{
//在Catch时尽可能在最下面放上最大的异常Exception 以免捕获不到;
//在处理异常的时候推荐积极的打印异常做好判断然后打印;
//Catch 块 Catch 可以有多个
}catch(ExceptionName e1)
{
//Catch 块 Catch 可以有多个
}finally{
// 最后要执行的代码 可有可无
}
Catch 语句包含要捕获异常类型的声明。当保护代码块中发生一个异常时,try 后面的 catch 块就会被检查。
如果发生的异常包含在 catch 块中,异常会被传递到该 catch 块,这和传递一个参数到方法是一样。
finally 关键字用来创建在 try 代码块后面执行的代码块。无论是否发生异常,finally 代码块中的代码总会被执行。在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。比如IO流时发生异常最后在finally内关闭IO流;
注意下面事项:
在 Java 中你可以自定义异常。编写自己的异常类时需要记住下面的几点。
//自定义异常类
public class MyException extends Exception{
private int detail;//传递的值
public MyExcrption(int a){
this.detail = a;
}
//打印异常信息
public String toString(){
return "MyException{"+detail+"}";
}
}
到这里那记录的就结束了,这是跟着狂神老师学习记录的,狂神的B站教学视频:狂神B站
附:Java知识体系学习思维图