Java
Java基本语法
特点
面向对象 oop
健壮,强类型机制
跨平台,即可以跨系统运行class文件,windows和Linux都可以
Java语言是解释性的,JavaScript,PHP,java是解释性,编译性语言是c,c++
解释性语言,编译后的代码不能直接被机器执行,需要解释器来执行
编译性语言,编译后的代码可以直接被机器执行,编译后的是二进制文件,所以可以直接执行
Java的运行机制
先编写.java文件
编译为.class文件
JVM,java虚拟机,因为有了JVM,同一个Java程序在三个不同的操作系统中都可以执行
JDK
java development kit Java开发工具包
JDK=JRE + Java的开发工具[java,javac,javadoc,javap等]
jdk包含了jre,jre包含了jvm,所以安装了JDK,就不用安装JRE了
但是从jdk9开始,jdk目录中就没有单独的jre目录了,因为jre作为一个运行时,里面不需要包含太多的东西浪费空间,降低运行效率,再jdk9的时候使用模块化技术,让开发者能按照自己的应用创建一个最小的运行时jre(比如一个微服务的部署,仅仅需要一个非常小的runtime,而不是像之前一样不管应用复杂还是简单,都需要一个近百M的jre运行),这样提高了运行效率
javac 编译工具 java 运行工具 jdb 调试工具 jhat 内存分析工具
JRE
- JRE = JVM + Java的核心类库
- java runtime environment Java运行环境
- 包括JVM和Java程序所需要的核心类库等,如果想要运行一个开发好的Java程序,计算机中只需要安装JRE
java快速入门
// 这是java快速入门
public class hello{
//编写一个main方法
public static void main(string[] args){
System.out.println("hello,world~")
}
}
表示hello是一个类,是public公有的类,这个类的名字要和文件名相同
大括号表示一个类的开始和结束,hello{}表示一个类的开始和结束
public static void main()表示是一个主方法,即我们程序的入口
main(){…}大括号表示方法的开始和结束
System.out.println(“hello world
“);表示输出”hello,world“到屏幕分号**;**代表语句的结束
如果程序class后的变量和文件名不一致,会报错“错误: 类HelloWorld是公共的, 应在名为 HelloWorld.java 的文件中声明”,这个时候,我们需要将文件名和类名相同
编码问题
出现乱码编译不过去,javac编译之后没有.class文件的原因可能就是编码问题
win+r打开terminal,右键点击属性,可以查看到编码(当前代码页那一栏)
因为当前控制台设置的编码是gbk,所以只认gbk,其它的编码无法识别,即无法过编译
所以在vscode中ctrl+shift+p,打开控制台,编码,选择编码重新打开,使用和terminal一样的编码打开,(可以都用gbk)
运行问题
用javac 加上文件名可以编译
java 加上类的名字可以运行
注意,在运行的时候不能加.class,因为开发者写底层代码的时候,实际运行的是某个类,而不是某个文件
如果想要类名和文件名不一致,必须在声明类时不带public,例如:
public class Demo{} -> class Demo{}
一个java文件中可以写多个class类,但是只能有一个类带public,有多少类就会生成多少class文件
main方法必须写在带public的类中
Java执行流程分析
- 编写.java文件(源文件)
- 用javac命令将上一步编写的.java文件编译为.class文件(字节码文件)(javac命令的本质就是调用javac.exe)
- 用java命令运行出结果,运行的本质就是将.class文件装载到jvm虚拟机中执行
- 每一次更改之后必须重新编译,将jvm中的.class文件进行更新,才能真正地输出更新之后的结果,否则只保存,不会更新
Java开发细节
Java源文件以.java为拓展名,源文件的基本组成部分是类(class),例如本类中的Hello类
Java应用程序的执行入口是main()方法,有固定的书写格式
public static void main(String[] args){...}
Java严格区分大小写
Java每一条语句都是以分号结尾
大括号都是成对出现的,缺一不可,习惯先写{}再写代码
一个源文件最多只能有一个public类,其它类的个数不限,例如我只能写一个public类,然后写多个前面没有限制的类
编译后,每一个类,都对应一个.class文件
如果源文件包含一个public类,则文件名必须按照该类名命名,类的名字决定了文件名
一个源文件最多只能有一个public类,其它类的个数不限,也可以将main方法卸载非public类中,然后指定运行非public类,这样入口方法就是非public的main方法,而且一个源文件中可以包含多个main方法,即可以在public类中写完main后,在其它类中接着写main方法
因为javac编译后是一个个的.class文件,调用时是单个进行调用,所以调用时,需要使用 java + 类名 进行逐个调用
类、方法的注释,要以javadoc的方式来写
非javadoc的注释,往往是给代码的维护者看的,着重告诉读者为什么这样写,如何修改,注意什么问题
码风缩进问题:选中后,按tab键整体右移,选中后,按shift+tab整体左移
码风书写问题:运算符和 = 两边各习惯性地加一个空格,比如 2 + 4 * 5 + 345 - 89
源文件使用utf-8编码,用gbk是用dos不得已使用,所以以后开发使用utf-8编码
行宽不要超过80个字符,每一行不要超过80个字符
代码编写次行风格和行尾风格
学习方法
按需学习
先看看学过的传统技术能不能解决,新技术和传统技术进行比较,能解决但是不完美还是不能解决
引出我们学习的新技术和知识点
学习新技术或者知识点的基本原理和基本语法,不要在一开始就考虑细节
快速入门(基本程序,增删改查)
开始考虑研究技术的注意事项,使用细节,使用规范,如何优化,研究框架之类的放到最后
Java转义字符
\t 制表符
\n 换行,注意和\r的区别
\\ 一个\
\" 一个"
\' 一个'
\r 将光标跳转到该行开头,reverse,只是回车,没有换行,而且不是删除该行后,是替换前面的字符,而不是删除
初学Java易犯错误
- 找不到文件:文件名字写错了,或者终端的当前位置不对
- 主类名和文件名不一致
- 缺少分号
Java基本概念(第一个Java程序)
概念
- 对象:对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
- 类:类是一个模板,描述一类对象的行为和状态
- 方法:方法就是行为,一个类可以有很多方法。逻辑运算,数据修改以及所有动作都是在方法中完成的。
- 实例变量:每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
第一个Java程序
- public class Demo03Helloworld:定义一个类
- class:代表的就是类,类是Java程序最基本的组成单元,所有代码都需要在class中写
- class后面跟的名字叫做类名,要求类名和Java文件名保持一致
- public static void main(String[] args):叫做main方法,是程序的入口,jvm执行代码,会从main开始执行
- System和String的首字母S要大写
养成习惯
- 大小写敏感:Java是大小写敏感的
- 类名:对于所有类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母都应该大写,My First Java Class
- 方法名:所有的方法名都应该以小写字母开头,如果方法名含有若干单词,则后面的每个单词首字母大写(只是第一个单词小写,后面的每一个单词的首字母都要大写)
- 源文件名:源文件名必须和类名相同,当保存文件时,应该使用类名作为文件名保存
- 主方法入口:所有的Java程序都是由public static void main(String[] args)方法开始执行
Java标识符
类名,变量名,方法名都被称作标识符
所有标识符都应以字母,美元符,或者下划线作为首字母,不能用数字作为标识符的首字母
[a-z][A-Z] $ _
首字母之后可以是字母,美元符,下划线和数字的任何字符组合
关键字不能用作标识符
大小写敏感
关键字
注释
- 单行注释 //
- 多行注释 /* */,多行注释里面不允许由多行注释嵌套
- 文档注释/** */,第二个星号和第三个星号之间写注释内容
文档注释
注释内容可以被JDK提供的工具javadoc所解析,生成一套以网页文件型式体现的该程序的说明文档,一般写在类
可以使用javadoc工具来生成信息,并且输出到HTML文件中。
常用的标签
@author @exception @link @return @see @serial @version
javadoc标签
由 /** 开始 由 */结束,在开始的/**之后,第一行或几行是关于类,变量,和方法的主要描述,可以不加@标签写非标签的注释
之后可以包含一个或多个各式各样的**@标签**,每一个@标签必须在一个新行的开始或者在一行的开始紧跟星号 *
/***这是一个javadoc * @author runoob * @version 1.2 */
javadoc的输出:javadoc将你的Java程序的源代码作为输入,输出一些包含你程序注释的HTML文件
每一个类的信息将在独自的HTML文件里,javadoc也可以输出继承的树形结构和索引
由于javadoc的实现不同,工作也可能不同
每一个javadoc文档注释都在描述的项目的前面
可以在每一个class中都写一个javadoc
结果将在 class名字.html 中找到
基本数据类型
两大数据类型
- 内置数据类型
- 引用数据类型
内置数据类型
- 8种基本类型:6种数字类型,1种字符类型,1种bool类型
byte 8位,有符号的,以二进制补码表示的整数
short 16位
int 32位
long 64位
float 32
double 64
boolean 只有两个取值,true和false,表示一位的信息,默认值为false
char 16
引用类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。
- 引用类型指向一个对象,指向对象的变量是引用变量。
- 这些变量在声明时被指定为一个特定的类型,比如 Employee、Puppy 等。变量一旦声明后,类型就不能被改变了。
- 简单地说,就是自己写的对象和数组就是引用数据类型
- 所有引用类型的默认值都为null
java常量
在Java中使用final关键字来修饰常量,声明方式就是在变量声明方式前面加上final
final double PI = 3.14
用0来表示8进制,0x表示16进制,不能是o和O
字符串常量和字符变量都可以包含任何 Unicode 字符。
自动类型转换
整型,实型,字符型数据可以混合运算,运算中,不同类型的数据先转换为同一类型,然后进行运算
转换从低级到高级
低 ------------------------------------> 高 byte,short,char—> int —> long—> float —> double
转换规则
- 不能对bool类型进行转换
- 不能把对象类型转换成不相关类的对象。???
- 在把容量大的类型转换为容量小的类型时必须使用强制类型转换
- 转换过程中可能出现溢出或者精度损失
- 浮点数转换为整数时通过舍弃小数得到,而不是四舍五入
- 该区域的数据/值可以在同一类型范围内不断变化
强制类型转换
条件是转换的数据类型必须是兼容的
格式
(type)value int i1 = 123; byte b = (byte)i1;
基本数据类型和String类型的转换
基本数据类型转String类型
语法:将基本类型的值 + ”“ 即可
public class StringToBasic{ public static void main(String[] args){ int n1 = 100; String str1 = n1 + ""; String str2 = "abc"; System.out.println(str1 + " " + str2); } }
注意这个地方的String的首字母是大写的
String类型转基本数据类型
语法:通过基本类型的包装类调用parseXXX方法即可
public class StringToBasic{ public static void main(String[] args){ String s1 = "100"; int a = Integer.parseInt(s1); System.out.println(s1); } }
parse:解析,parseInt:将字符串参数作为有符号的十进制整数进行解析,除了第一个字符可以是用来表示负值的ASCII减号外,其余的字符串中的字符都必须是十进制整数。
parseDouble:
public class StringToBasic{ public static void main(String[] args){ String s1 = "123.111"; double dou1 = Double.parseDouble(s1); System.out.println(dou1); } }
还有Float.parseFloat , Long.parseLong,Byte.parseByte等等
常量运算除法特殊
前后如果都是整数,结果只取整数部分
前后只要有一个带小数点,结果就是正常小数了
```java
System.out.println(“10/3”) //结果为3,不为小数
System.out.println(“10.0/3”) //结果为小数
System.out.println(“10/3.0”) //结果为小数## 变量类型 1. 使用逗号来隔开声明多个同类型变量,和c不同的是:可以在定义多个变量的同时,写到一行,统一赋值 ```java int a, b, c; // 声明三个int型整数:a、 b、c int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值 byte z = 22; // 声明并初始化 z String s = "runoob"; // 声明并初始化字符串 s double pi = 3.14159; // 声明了双精度浮点型变量 pi char x = 'x'; // 声明变量 x 的值是字符 'x'。
java支持的变量类型
类变量:独立于方法之外的变量,用static修饰
实例变量:独立于方法之外的变量,不过没有static修饰
局部变量:类的方法中的变量
public class Variable{ static int a = 1; //类变量 String str="hello world"; //实例变量 public void method(){ int i = 0; //局部变量 } }
局部变量
- 局部变量在方法,构造方法,或者语句块被执行的时候创建,当他们执行完后,变量会自动销毁
- 访问修饰符不能用于局部变量 ???
- 局部变量只在声明它的方法、构造方法或者语句块中可见
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才能使用
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外
- 当一个对象被实例化之后,每个实例对象的值就跟着确定
- 实例对象的在对象创建的时候创建,在对象销毁的时候销毁
- 实例对象的值至少应该被一个方法,构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息
- 实例对象可以声明在使用前和使用后
类变量,静态变量
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。
常量和静态变量的区别
- 常量前面用final修饰,静态变量前面用static修饰
(94条消息) 静态变量和常量的区别_haobaworenle的博客-CSDN博客_静态变量和常量有什么区别
静态变量和实例变量的区别
语法上:静态变量前面用static关键字,实例变量前面不用
实例变量属于某个实例对象,只有当实例化后才能创建实例变量
而静态变量不属于实例对象,而是属于类,只要程序加载了类的字节码,不用创建实例对象,就会被分配空间,静态变量就能使用
Java修饰符
- 修饰符用来定义类、方法或者变量,通常放在语句的最前端。
访问修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。
运算符
>>> 按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以0补充
>> 按位右移操作符,移动得到的左边空位不会以0补充
- 注意逻辑运算符 && 和 || 带来的短路特性
instanceof 运算符
该运算符用于操作对象实例,检查该对象是否是一个特定的类型。
例如,检查是否为int类型,就是 var instanceof int,返回值是一个bool值,true或false,所以可以判断对象的类型(类类型或接口类型)
String name = "James"; boolean result = name instanceof String; //由于name是String类型,所以返回值为true
如果被比较的对象兼容右侧类型,该运算符仍然返回true,例如下面的例子,子类继承了父类,所以兼容于父类,所以子类instanceof父类
class Vehicle{} public class Car extends Vehicle{ public static void main(String[] args){ Vehicle a = new Car(); boolean result = a instanceof Car; System.out.println(result); } }
循环结构
- while
- do while
- for
- break
- continue
public class Test{
public static void main(String[] args){
int x = 10;
}
do{
System.out.println("value of x : " + x);
x++;
System.out.println("\n");
}while(x < 20);
}
public class Test{
public static void main(String[] args){
int x = 10;
while (x < 20){
System.out.println("value of x :" + x); //这个地方的 string + x 的用法和一个整数 + ""可以成为字符串一样
x++;
System.out.println("\n");
}
}
}
public class Test{
public static void main(String[] args){
int [] numbers = {10,20,30,40,50};
for(int x : numbers){
System.out.println(x);
System.out.println(" , ");
}
System.out.println("\n");
String [] names = {"james","Larry","TOM"};
for(int x : names){
System.out.println(x);
System.out.println(" , ");
}
System.out.println("\n");
}
}
上面for循环使用的是类似于c++的范围遍历的增强型for循环
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配,其作用域限定在循环语句块,其值与此时数组元素的值相等
表达式:表达式是要访问的数组名,或者是返回值为数组的方法
for(声明语句 : 表达式){ //代码语句; }
break主要用于循环语句或者switch语句中,用来跳出整个语句块
break跳出最里层的循环,并且继续执行该循环下面的语句(执行该层循环之外的其它语句,跳出此循环)
public class Test{ public static void main(String[] args){ int [] numbers = {1,2,3,4,5}; for (int x : numbers){ if(x == 3){ break; } System.out.println(x); System.out.println("\n"); } } }
continue 让程序立刻跳转到下一次循环的迭代,而不是跳出整个循环
在for循环中,continue使程序立即跳转到更新语句
while和do while中,程序立即跳转到bool表达式的判断语句
public class Test{ public static void main(String[] args){ int [] numbers = {10, 20, 30, 40, 50}; for(int x : numbers){ if(x == 30){ continue; } System.out.print(x); } System.out.println("\n"); } }
条件语句
- if else
- switch case
- if ,else if, else
public class Test{
public static void main(String[] args){
int x = 10;
if (x < 20){
String a = "yes";
System.out.println(a);
}
else{
String a = "false";
System.out.println(a);
}
}
}
public class Test{
public static void main(String[] args){
int x = 30;
if(x == 10){
System.out.println("10");
}
else if(x == 20){
System.out.println("20");
}
else{
System.out.println(x);
}
}
}
- 注意default的先后顺序:先全部判断一遍case语句,在没有case语句的值和变量值相等时执行,default分支不需要break
public class Test{
public static void main(String[] args){
char grade = 'C';
switch(grade){
case 'A' :
System.out.println('A');
break;
case 'B' :
System.out.println('B');
break;
case 'C' :
System.out.println('C');
break;
default :
System.out.println("未知等级");
}
}
}
return
return 语句如果用在main函数中,则会跳出程序
public class Return { public static void main(String[] args) { int x = 0; for (int a = 0; a <= 10; a++) { x += a; if (x == 3) { System.out.println(x); return; } } } }
String类
在Java中字符串属于对象,Java提供了String类来创建和操作字符串。
创建字符串
String str = "Runoob";
也可以和其它对象一样,使用关键字和构造方法来创建String对象
String str2 = new String("Runoob");
String创建的字符串存储在公共池中,而new创建的字符串对象在堆上
注意:String类是不可改变的,所以一旦创建了String对象,那么它的值就无法改变了。
如果需要对字符串做很多修改,那么应该选择使用 StringBuffer & StringBuilder 类。
获取字符串长度
使用length方法,获取有关对象的信息的方法被称为访问器方法
语法:
int len = str_name.length;
- 注意:对象.length,后面不加括号
连接字符串
使用concat连接字符串
string1.concat(string2); "我的名字是".concat("syk");
使用 + 操作符来连接字符串
"Hello" + "syk" + "!";
键盘输入语句
在input.java中,需要一个扫描器(对象),Scanner,来接收用户输入的数据,使用键盘输入语句来获取
步骤
1. 导入该类的所在包,java.util.* 要引用一个类,就必须导入一个包 2. 创建该类的对象(声明变量) 3. 调用里面的功能
```java
import java.util.Scanner;public class Input {
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); // new创建一个对象,最前面的是表明是Scanner类的名字为scanner的变量 System.out.println("请输入名字"); String name = scanner.next(); // next()是查找并返回来自此扫描器的下一个完整标记 System.out.println("请输入年龄"); int age = scanner.nextInt(); System.out.println("名字为" + name + "年龄为" + age); }
}
5. scanner是一个简单的文本扫描器 6. ```java import java.util.Scanner; Scanner scanner = new Scanner(System.in); datatype name = scanner.next(); // scanner.next(); 默认是string datatype name = scanner.nextInt(); // scanner.nextInt(); 只有表明是Int才会接收int datatype name = scanner.nextDouble(); // 只有表明是Double,才会接收double类型的数据
数组
声明数组变量
首先必须声明数组变量,才能在程序中使用数组。
datatype[] array; datatype array[];
建议使用datatype[] array_name的声明风格声明数组变量。 dataType arrayRefVar[] 风格是来自 C/C++ 语言 ,在Java中采用是为了让 C/C++ 程序员能够快速理解java语言。
创建数组
Java使用new操作符来创建数组
array_name = new datatype[arraysize];
上面语法做了两件事,第一:使用datatype[size]创建了一个数组,第二:把新创建的数组引用复制给变量array——name
声明和创建数组一步完成
datatype[] array_name
数组的引用
- 引用,使用,访问,获取 是一个意思
数组的动态初始化1
datatype[] name = new datatype[size];
数组的动态初始化2
- 有些时候可以在for循环的外面声明一个数组,但是分配内存是当某个条件满足的时候才去真正分配
- 第一步,先声明数组(声明时还没有分配空间,声明数组的名字的指针还没有指向任何空间)
- 此时该数组时null
int[] a;
int a[];
第二步,创建数组
只有new之后,才会分配内存空间,可以存放数据
数组名 = new 数据类型[大小]; a = new int[10];
数组的静态初始化
int a[] = {1,2,3...};
上面的用法等同于
int[] a; a = new int[n]; a[0]=1; a[1]=2;...
当知道数组有多少元素,具体值时才用静态方法初始化数组
数组detail
数组中的元素是相同类型的,如果在低精度数组中写了一个高精度数组,则会报错;如果在一个高精度数组中写了一个低精度数组,没有问题,自动转换
detail.java:3: 错误: 不兼容的类型: 从double转换到int可能会有损失 int a[] = { 1, 2, 3,3.3 }; ^ 1 个错误
数组下标必须在指定范围内使用,否则报:下标越界异常,比如 int[] arr = new int[5];则有效下标是0-4,即数组的下标,最小是0,最大是数组长度-1,否则数组越界,在编译的时候不会报错,当运行的时候才会报错
java.lang.ArrayIndexOutOfBoundsException
数组属于引用类型,数组行数据是对象
数组的赋值机制
基本数据类型的赋值,拷贝赋值
基本数据类型的赋值,赋值方式为拷贝
n2的变化不会影响到n1
int n1 = 10; int n2 = n1; int n2 = 1; //此时n1还是10,n2变为了1
数组赋值,引用赋值
数组在默认情况下是引用传递,赋的值是地址,赋值方式为引用赋值
引用赋值传递的是一个地址,arr2和arr1指向的是同一个地址,所以当对arr2的数组进行操作时,会对arr1产生影响
public class detail { public static void main(String[] args) { int[] arr1 = {1,2,3}; int[] arr2 = arr1; arr2[0] = 10; for(int i = 0;i < arr1.length;i++){ System.out.println(arr1[i]); //这个时候就会输出10,2, } } }
拷贝赋值和引用赋值的区别
jvm的内存分为:栈、堆、方法区
基本数据类型直接放在栈中,即值拷贝/传递在栈中进行
数组在定义的时候,赋的值并不是具体的值,而是一个地址,这个地址指向的时是堆中的一片空间
在内存中,只要分配了一个数据空间,一定会对应一个地址
引用传递也叫地址拷贝
数组拷贝
将int[] arr1 = {1,2,3} 拷贝到 arr2数组,要求数据空间是独立的
```java
int[] arr1 = {1,2,3};
int[] arr2 = new int[arr1.length];
// 遍历arr1,把每个元素拷贝到对应元素的位置
for(int i = 0;i < arr1.length;i++){arr2[i] = arr1[i];
}
### 处理数组 1. 数组的元素类型和数组的大小都是确定的,所以当处理数组元素时候,我们通常使用基本循环或者 For-Each 循环。、 #### For-each循环 1. For-each循环,加强型循环,可以在不使用下标的情况下遍历数组 ```java for(type element : array){ System.out.println(element); }
public class Testarray { public static void main(String[] args) { double[] myList = { 1.9, 2.9, 3.4, 3.5 }; for (double x : myList) { System.out.println(x); } } }
数组作为函数的参数
数组可以作为参数传递给方法
public class Print { public static void main(String[] args){ printArray(new double[]{1.2,1.2,3.3,44.4}); } public static void printArray(double[] array) { for (int i = 0; i < array.length; i++) { System.out.println(array[i] + " "); } } }
数组作为函数的返回值
- 数组作为函数的返回值,return返回的是一个地址
- 函数的返回值标明数据类型,int[] double[] float[]
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;
}
多维数组
数组的数组
String[][] str = new String[3][4];
多维数组的动态初始化基础
直接为每一维度分配空间
type[][] typename = new type[typelength][typelength]
从最高维开始,分别为每一维分配空间
String[][] s = new String[2][]; s[0] = new String[2]; s[1] = new String[3]; s[0][0] = new String("Good"); s[0][1] = new String("Luck"); s[1][0] = new String("to"); s[1][1] = new String("you"); s[1][2] = new String("!");
具体实现
public class Doublearr {
/**
* @param args
*/
public static void main(String[] args) {
// 静态初始化方法1
int c[][] = new int[2][3]; // 直接将行和宽定义出来的静态初始化
// 静态初始化2
int[][] d = { { 1, 1, 1, 1 },
{ 2, 2, 2, 2, 2 },
{ 3, 3, 3, 3, 3, 3 },
};
// 动态初始化1
// 先声明这是一个二维数组,然后再使用new来定义(开辟空间)
int a[][]; // 先声明这是一个二维数组
a = new int[2][3]; // 再用new去开辟空间
// 动态初始化2
// 可以出现列数不确定的情况(行数必须确定)
// 即数组的第一维必须指出,第二维可以不写
int arr[][] = new int[5][]; // 第二维可以不去定义
for (int i = 0; i < arr.length; i++) { // 遍历arr的每一个一维数组
// 给每个一维数组开空间
// 如果没有给一维数组new,那么arr[i]就是null
arr[i] = new int[i + 1];
for (int j = 0; j < arr[i].length; j++) {
arr[i][j] = j;
System.out.print(arr[i][j]);
}
System.out.println();
}
System.out.println(arr.length);
}
}
逆序数组
思路1
把arr[0]和arr[n-1]进行交换,双指针
```
public class Reverse {public static void main(String[] args) { int[] arr = { 1, 2, 3, 4, 5 }; int temp = 0; int len = arr.length; for(int i = 0;i < arr.length / 2;i++){ temp = arr[len - 1 - i]; arr[len - 1 - i] = arr[i]; arr[i] = temp; } for (int x : arr) { System.out.print(x); } }
}
3. 还有一种是重新开辟内存空间,逆序遍历arr,将每个元素拷贝到arr2的元素中(逆序遍历,顺序拷贝) ```java public class Arrreverse { public static void main(String[] args) { int[] arr1 = { 1, 2, 3, 4, 5 }; int[] arr2 = new int[arr1.length]; for (int i = arr1.length - 1,j = 0; i >= 0; i--,j++) { //注意,当一重循环中有多个循环变量时,只需要定义一次循环变量的类型,例如已经定义了int i,就不能再定义j 为int 了,默认为相同类型 arr2[j] = arr1[i]; } for (int x : arr2) { System.out.print(x); } } }
数组添加1
要求:实现动态地给数组添加元素效果,实现对数组的扩容。
原始的数组使用静态分配 int[] arr = {1,2,3}; 增加元素,直接放在数组的最后 arr_new = {1,2,3,4};
注意:静态初始化的数组下标的最大值和最小值已经固定,如果强制赋值,例如上面的例子,arr[3] = 4,会报数组越界的错误,即静态数组的大小不能改变
思路:定义一个新的数组,int[] arrNew = new int[arr.length + 1]; 令新数组扩容
然后遍历arr数组,依次将arr元素拷贝到arrNew数组
将4赋值给arrNew[arrNew.length - 1];
体现是改变的原来的数组,而不是新数组,最后要让arrNew指向原先的arr
arr = arrNew;
原来的没有被引用的空间就会被销毁
public class Up{
public static void main(String[] args){
int[] arr = {1,2,3};
int[] arr_new = new int[arr.length + 1];
for(int i = 0;i < arr.length;i++){
arr_new[i] = arr[i];
}
arr_new[arr_new.length - 1] = 4;
// 让arr 指向arr_new
arr = arr_new;
for(int x : arr){
System.out.print(x);
}
}
}
数组扩容2
使用户可以动态添加元素进数组
1. 创建一个Scanner可以接受用户输入 2. 因为用户什么时候退出,不确定,使用do-while + break来控制
```java
import java.util.Scanner;public class Up {
public static void main(String[] args) { Scanner myscanner = new Scanner(System.in); int[] arr = { 1, 2, 3 }; do { int[] arrNew = new int[arr.length + 1];// 先扩容 for (int i = 0; i < arr.length; i++) { // 再通过遍历,逐个赋值给arrNew arrNew[i] = arr[i]; } System.out.println("请输入你要添加的元素"); int num = myscanner.nextInt(); arrNew[arrNew.length - 1] = myscanner.nextInt();// 添加最后一个元素 arr = arrNew; // 询问客户是否还要继续添加 if (num == 1) { break; } } while (true); for (int x : arr) { System.out.print(x); } }
}
#### 数组缩减 ```java import java.util.Scanner; public class Reduce { public static void main(String[] args){ int[] arr = {1,2,3,4,5}; Scanner myscanner = new Scanner(System.in); String a; do{ a = myscanner.next(); int[] arrNew = new int[arr.length - 1]; for(int i = 0;i < arr.length - 1;i ++){ arrNew[i] = arr[i]; } arr = arrNew; }while(a != "1"); //while内部写的是执行循环的条件,是令循环继续下去的条件 for(int x : arr){ System.out.print(x); } } }
和数组扩容的思路相同
acwing补充
Java和c++,python的不同点
- java中的函数必须定义到类中
- c++的函数可以定义到类外面
static
- 一个方法如果加上了static,那么这个方法就是绑定到了类本身
- 和global类似
- static的意思是从这个类实例化出来的对象共享属性
- 类方法和类变量
- 静态方法中必须只能调用静态方法和静态属性,不能调用非静态的,即必须加上static
接口
- 接口就是用来规范化方法的
- 接口虽然是类,但是不能实例化
- 接口只是对方法进行一个声明,不能具体写实现方法
- 所有implements接口的类必须实现所有接口中的所有方法都实现,接口中的方法都是abstract的,即没有具体写明的
继承
- 如果一个游戏有很多英雄
- 英雄有公共(都有)的技能
- 那么其它英雄的技能可以继承自一个基类,这个基类中写共有的方法
- 基类就是父类
- 继承的作用就是为了不去重复写,公共的放到父类中去
多态
- 同一个类的同一个函数可能会有不同的行为