JavaSE基础知识
一。简介
本篇文章是在学完c语言后进行Java的新章节文章,所以会有一些知识点会和c语言很相似,因此有些知识点如果解释的不清楚,大家可以看一下我之前写过的关于c语言的博客
下面来了解一下JavaSE:
其实Java有三个版本的分类,分别为JavaSE,JavaEE,JavaME。JavaSE的英文全称叫作:Java platform, standard Edition 也叫Java标准版,是用做电脑运行的软件。JavaEE的英文全称叫作:Java platform,Enterprise Edition,也叫Java企业版,是用来做网站的。JavaEE是用来做手机软件的。要注意的是JavaSE是Java的基础,不管哪个分类都要对JavaSE进行学习和理解。
二。数据类型与变量
1.字面常量
常量即程序运行期间,固定不点的量就叫做常亮
分类:
1.字符串常量:由括号括起来的。如:“123”,“hello”
2.整形常量:如:123,666,
浮点型常量:如3.14
字符常量:就是用单括号扩起来的当做字符,如:‘a’
布尔常量:只有true和false两种
空常量:null
2.数据类型
在Java中数据类型主要分为两类:基本数据类型和引用数据类型。
基本数据类型有四类:整型、浮点型、字符型以及布尔型
这些基本和c语言的用法相似,如需了解,请看我之前写的 c语言基础(上)
3.变量
(1)整型变量
- int不论在何种系统下都是4个字节
- 推荐使用方式一定义,如果没有合适的初始值,可以设置为0
- 在给变量设置初始值时,值不能超过int的表示范围,否则会导致溢出
- 变量在使用之前必须要赋初值,否则编译报错
- int的包装类型为 Integer
(2)长整型变量
- 长整型变量的初始值后加L或者l,推荐加L
- 长整型不论在那个系统下都占8个字节
- long的包装类型为Long
(3)浮点型
在java中,int除以int还是int(会直接舍弃小数部分),如果想要得到小数点以后的数字,则把int类型改完double类型
在单精度浮点型中一定要在数据赋值时后面加上f,例如:float num=1.0f;
float类型占4个字节 ,double类型占8个字节
float的包装类型为Float
double的包装类型为Double
(4)字符型变量:
java中使用单引号+单个字母的形式来表达字符字面值
char 的包装类型为Character
注意:一个汉字占两个字节
(5)布尔类型:
布尔类型常用来表示真假
boolean只有两种取值,true表示真,false表示假
boolean没有明确表示占几个字节
boolean的包装类型是Boolean
(6)字节型:
byte在任何系统下都占一个字节
byte的范围是-128到127
byte的包装类型为Byte
4.类型转换
(1)自动类型转换(隐式)
定义:代码不需要任何处理,编译器会自动进行处理
规则:数据范围小的转换为数据范围大的时会自动进行
注意:浮点型默认情况下是double类型
int a=0;
long b=0;
b=a;
a=b;
b=a处,是把a的值赋给b,因为b和a都是整形,a的范围小,b的范围大,所有编译器会自动的将a的int型转换为long型
a=b处,是把b的值赋给a,long的范围比int大,因此会造成数据的丢失,编译会报错
(2)强制类型转换(显式)
规则:数据范围大的到数据范围小的
int a=10;
long b=20;
b=a;//小的转换为大的,是自动类型转换
a=(int)b//大的转换为小的,是强制类型转换,否则编译报错
5.类型提升
(1)int与long之间:int会被提升为long
int a=10;
long b=20;
int c=a+b;//报错
long d=a+b;//成功
那么为什么int c会报错呢,因为a是int,b是long,a+b时会把a先转换成long类型,所以最后a+b得到的是一个long类型的和,而c是int类型,因此会丢失数据
总结:不同类型之间的数据混合运算,范围小的会提升为范围大的
(2)byte与byte的运算
byte a=10;
byte b=20;
byte c=a+b;
System.out.println(c);
这时会报错
结论:虽然a和b的类型都是byte类型,但是计算a+b时会先将a和b提升为int类型,再计算,所有c用byte接受就会发生出现数据丢失,从而报错
原因:由于计算机的 CPU 通常是按照 4 个字节为单位从内存中读写数据. 为了硬件上实现方便, 诸如 byte 和 short
这种低于 4 个字节的类型, 会先提升成 int, 再参与计算。
【类型提升小结】
- 不同类型的数据混合运算, 范围小的会提升成范围大的。
- 对于 short, byte 这种比 4 个字节小的类型, 会先提升成 4 个字节的 int , 再运算。
6.字符串类型
(1)在Java中使用String定义字符串类型,比如:
String s1=“hello world”
注意:String是大写开头
(2)int转成String
int num=10;
String str1=num+"";//写法1
String str2=Sring.ValueOf(num);//写法2
(3)String转换成int
String str="100";
int num=Integer.parselnt(str);
(4)拼接
int a=10;
int b=20;
System.out.println("a=" + a + "b=" + b);//a=10 b=20
System.out.println("a+b="+a+b);//a+b=1020
System.out.println(a+b+"a+b");//30a+b(先运算,后拼接)
总结:字符串 拼接 其他=字符串
三。逻辑控制
1.分支结构
(1).if语句
语法格式(1)
if(布尔表达式){
//语句
}
此布尔表达式的结果为true,如果不是则不输出
语法格式(2)
if(布尔表达式){
//语句;
}else{
//语句;
}
此布尔表达式的结果为true则执行if语句的内容,否则执行else语句的内容
语法格式(3)
if(布尔表达式){
//语句;
}else if{
//语句;
}else{
//语句;
}
练习:判断一个数是奇数还是偶数
int num=0;
if(num/2=0){
System.out.println("偶数");
}else{
System.out.println("奇数")
}
(2)switch语句
基本语法:
switch(表达式){
case 常量值1:{
语句1;
break;
}
case 常量值2:{
语句2:
break;
}
case 常量值3:{
语句3;
break;
}
default:{
内容都不满足时使用;
break;
}
}
看到这里大家一定会发现Java中的switch语句的形式和c语言中的switch语句是相同的语法形式
同时我们要注意switch括号内的内容是有限制的,下面进行介绍:
(1)基本类型:byte,char,short,int 注意不能是long类型
(2)引用类型:string常量串,枚举类型
2.循环结构
(1)while循环
基本语法格式:
while(循环条件){
循环语句;
}
这里的循环条件其实就是布尔类型的,如果循环条件是true则进入循环,如果不是则结束循环
例子1:计算1-100的和
int i=1;
int sum=0;
while(i<=100){
sum+=i;
i++;
}
System.out.println(num);
如果题目改完计算1-100的奇数和,则把i++改为i+=2;这样就可以实现计算1-100的奇数和了
如果题目改成求偶数和,则把i=1改为i=2,再把i++改为i+=2
例子2:计算5的阶乘:
int n=1;
int sum=0;
while(n<=5){
sum*=n;
n++;
}
System.out.println(num);
sum*=n就是阶乘的写法
例子3:计算1!+2!+3!+4!+5!
int i=1;
int sum=0;
while(i<=5){
int n=1;
int ret=1;
while(n<=i){
ret*=n;
n++;
}
sum+=ret;
i++;
}
(2)continue语句
continue的功能就是跳过这次循环,直接进入下一次循环
例子:找到100-200中所有3的倍数:
int num=100;
while(num<=200){
if(num%3==0){
num++;
continue;
}
System.out.println(num);
}
此处的continue就是在每一次进行完num++,就立即进入下一次循环,不会直接打印num
(3)for循环
语法格式:
for(表达式1;布尔表达式2;表达式3){
表达式4;
}
例1:计算1-100的和
int i=0;
int sum=0;
for(i=0;i<=100;1++){
sum+=i;
}
System.out.println("sum="+sum);
例2:计算5的阶乘
int i=1;
int sum=1;
for(i=1;i<=5;i++){
sum*=i;
}
System.out.println("sum="+sum);
例3:计算1!+2!+3!+4!+5!
int i=1;
int sum=0;
for(i=1;j<=5;i++){
int j=1;
int set=1;
for(j=1;j<=i;j++){
set*=j;
}
sum+=set;
}
3.输入输出
使用scanner读取字符串/整数/浮点数
import java.util.Scanner;//使用输入时,一定要在代码最前面加上这句话
Scanner sc=new Scanner(System.in);//一定要写这一行,其中的sc是可以自定义改变的
System.out.println("输入你的名字");
String name=sc.nextLine();
因为这里需要输入一个字符串,所以是string,并且还有nextLine
如果输入一个整数,则最前面要把string改为int,并且后面是nextInt
如果输入一个浮点数,则最前面要把string改为float,并且后面是nextFloat
3.练习题
(1)猜数字游戏
系统自动生成一个随机整数(1-100), 然后由用户输入一个猜测的数字. 如果输入的数字比该随机数小, 提示 “低
了”, 如果输入的数字比该随机数大, 提示 “高了” , 如果输入的数字和随机数相等, 则提示 “猜对了” .
import java.util.Random;
import java.util.Scanner;
public class Text{
public static void main(string[]args){
Random random=new Random();//默认种子是系统时间
Scanner sc=new Scanner(System.in);
int toguess=random.nextInt(100);//随机生成一个1-100的数字
while(true){
System.out.println("请输入要输入的数字");
int num=sc.nextInt();
if(num<toguess){
System.out.println("低了");
}else if(num>toguess){
System.out.println("高了");
}else(num=toguess){
System.out.println("猜对了");
break;
}
}
}
}
这里其实引进了一个新的概念,就是随机数的写法:
import java.util.Random;
Random random=new Random();
int toguess=random.nextInt(100);//100可改
其实可以发现随机数的写法与输入的写法很相似
import java.util.Scanner;
Scanner sc=new Scanner(System.in);
int num=sc.nextInt();
通过两个对比可以发现写法极其相似,区别就是Scanner与Random,还有括号里面的内容
(2)计算分数的值
题目:计算1/1-1/2+1/3-1/4+1/5…+1/99-1/100 的值
public static void main(string[ ] args){
double sum=0;
int i=1;
int flg=1;
for(i=1;i<100;i++){
sum=sum+1.0/i*flg;
flg=-flg;
}
Sysem.out.println(sum);
}
主要应注意的是怎么把全部的加号改成有加有减,只有在引入一个值为1的变量,在每次循环的时候加一个负号就可以实现一加一减的格式
(3)用*组成X型图案
题目:
分析:
public class text{
public static void main(string[] args){
Scanner in =new Scanner(System .in);
while(in.hasNextInt()){
int a=in.nextInt();
for(int i=0;i<a;i++){
for(int j=0;j<a;j++){
if(i==j || (i+j)==a-1){
System.out.print("*");
}else{
System.out.print(" ")
}
}
System.out.println();
}
}
}
}
(4)输出乘法口诀表
题目:输出n*n的乘法口诀表,n由用户输入
public static void main(string[] args){
Scaner in=new Scanner(System.in);
int n= in.Scanner();
for(i=1;i<=n;i++){
for(j=1;j<=i;j++){
System.out.print(j+"*"+i+"="+j*i+" ")
}
System.out.println();
}
}
这里的 j 其实就是上面乘法口诀表图片的开头数字,而 i 就是每一次乘法的第二个数字
这里主要要理解如何打印最后的结果,和c语言的打印方式有一点不同
(5)水仙花数
题目:求出0-999之间的所有水仙花数并输出。(水仙花数是指一个三位数,其各位数字的立方和刚好等于该数本身,例如:153=13+53+3^3,则153是一个水仙花数
public static void main(string[ ] args){
for(int i=0;i<999999;i++){
int count =0;
int tmp=i;//tmp就相当于替罪羊,因为i如果变了,那么后面就不能进行立方和刚好等于该数本身的比较
while(tmp!=0){
count++;
tmp=tmp/10;
}
tmp=i;//tmp就相当于替罪羊,因为i如果变了,那么后面就不能进行立方和刚好等于该数本身的比较
int sum=0;
while(tmp!=0){
sum+=Math.pow(tmp%10,count);//下面有解析
tmp/10;
}
if(sum==i){
System.out.println(i);
}
}
}
想必有人会有疑问Math.pow(tmp%10,count);是什么,其实这个就是一个公式,表达的意思就是tmp%10的count次方,举个例子:Math.pow(2,3)其实就是表示2的3次方(2^3)
四.方法的使用
1.方法概念及应用
(1)什么是方法
方法就是一个代码片段. 类似于 C 语言中的 “函数”。方法存在的意义(不要背, 重在体会):
- 是能够模块化的组织代码(当代码规模比较复杂的时候).
- 做到代码被重复使用, 一份代码可以在多个位置使用.
- 让代码更好理解更简单.
- 直接调用现有方法开发, 不必重复造轮子.
(2)方法的定义
语法格式:
修饰符 返回值类型 方法名称([参数类型 形参 ...]){
方法体代码;
[return 返回值];
}
例子:实现一个两个整数相加的方法:
public class Method{
public static int add(int x,int y){
return x+y;
}
}
这里的public static就叫做修饰符,现阶段直接使用这个作为固定搭配
Int 就是返回值类型
add就是方法名称
(Int x,int y)里的x和y就是形参
**注意:**在java当中,方法必须写在类之中,方法不能嵌套定义,没有方法声明这一说,方法的命名采用小驼峰的形式
(3)方法调用的执行过程
例子:计算1!+2!+3!+4!+5!
public static void main(String[] args){
int sum=0;
for(int i=1;i<=5;i++){
sum+=fac(i)
}
System.out.println("sum="+sum);
}
public static int fac(int n){
System.out.println("计算n的阶乘中n!="+n);
int result=1;
for(int m=1;m<=n;m++){
result*=m;
}
return result;
}
2.方法的重载:
(1)为什么需要进行方法的重载:
public stactic void main (string[] args){
int a = 10;
int b = 20;
int ret = add(a, b);
System.out.println("ret = " + ret);
double a2 = 10.5;
double b2 = 20.5;
double ret2 = add(a2, b2);
System.out.println("ret2 = " + ret2);
}
public static int add(int x, int y) {
return x + y;
}
}
// 编译出错
Test.java:13: 错误: 不兼容的类型: 从double转换到int可能会有损失
double ret2 = add(a2, b2);
由于参数类型不匹配, 所以不能直接使用现有的 add 方法.
(2)方法重载的概念
在java中如果多个方法的名字相同,参数列表不同,则称该几个方法被重载了
例子:
public static void main(string[] args){
add(1,2);
add(1.5,1.2);
add(1.5,1.2,2.3);
}
public static int add(int x,int y){
return x+y;
}
public static double add(double x,double y){
return x+y;
}
public static double add(int x,int y,int z){
return x+y+z;
}
注意:
1.方法名必须相同
2.参数列表必须不同(参数的个数,参数的类型,参数的顺序)
3.与返回值类型无关
五.数组的定义与应用
1.数组的创建
(1)格式
动态初始化:在创建数组时,直接指定数组中元素的个数
int[] array = new int[10];
这个格式是指明了数组中有10个元素,并且初始化值全为0
静态初始化:在创建数组时不直接指定数据元素个数,而直接将具体的数据内容进行指定
int[] array=new int[]{0,1,2,3,4,5};
静态初始化虽然没有指定数组长度,但是编译器在编译中会根据{ }里的数据个数来自动生成数组长度
静态初始化时,{ }内的数据类型要与[ ]前的数据类型一致
静态初始化可以简写,可以把new int[]不写,就变成一下形式
int[]array={0,1,2,3,4,5}
静态和动态初始化可以分两步来写,但是省略模式不可以分两步来写
//动态数组
int[] array1;
array1 =new int[10];
//静态数组
int[] array2;
array2=new int[]{10,20,30,40,50};
2.数组的使用
(1)数组元素的访问
本质上和c语言是一个道理,空间编号都是从0开始,数组可以通过其下标来访问任意位置的元素
int[] array1=new int[]{10,20,30,40};
System.out.println(array1[0]);
System.out.println(array1[1]);
System.out.println(array1[2]);
System.out.println(array1[3]);
//也可以对括号中的元素进行修改
array1[0]=100;
System.out.println(array1[0]);//结果就是100
数组的下标是从0开始,介于[0,N) 之间不包括N,N为元素个数,不能越界
(2)遍历数组
所谓 “遍历” 是指将数组中的所有元素都访问一遍, 访问是指对数组中的元素进行某种操作
最简单直白的方式就是像上面数组元素访问的代码一样,利用下标逐个访问数组元素。
但是,这个方法存在缺陷,如果数组的元素过多,想遍历数组就要一个一个的输出,代码会感觉冗余且麻烦
因此,我们经常使用**循环来遍历数组**:
int array[]=new int[]{10,20,30,40,50};
for(int i=0;i<5,i++){
System.out.println(array[i]);
}
其实如果想要代码变得更灵活,可以通过数组对象.length来获取数组的长度
int array[]=new int[]{10,20,30,40,50};
for(int i= 0; i< array.length; i++){
System.out.println(array[i]);
}
当然还有一种更简单方便的格式来遍历数组,那就是使用for-each遍历数组
int array[]={10,20,30};
for(int x:array){
System.out.println(x);
}
3.引用变量和对象
(1)java虚拟机运行时数据区:
程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址
虚拟机栈(JVM Stack): 与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含
有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一
些信息。比如:局部变量。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。
本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局
部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的
堆(Heap): JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,
3} ),堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销
毁。
方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数
据. 方法编译出的的字节码就是保存在这个区域
(2)引用变量
public static void soew(){
int a=0;
int b=0;
int[]arr=new int[]{1,2,3};
}
在上述代码中,a、b、arr,都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。
a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。
array是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址。
从上图可以看到,引用变量并不直接存储对象本身,可以简单理解成存储的是对象在堆中空间的起始地址。通过该
地址,引用变量便可以去操作对象。有点类似C语言中的指针,但是Java中引用要比指针的操作更简单。
(3)实参和形参
例子:
public static void main(String[] args){
int[] array={1,2,3,4};
func();
for(int x:array){
System.out.print(x+" ");
}
System.out.println();
}
public static void func(int[] array){
array=new int[]{11,22,33,44,55};
}
最后输出结果为1 2 3 4
这时会有人说,明明在func函数里对array数组进行了改变,为什么输出的还是变之前的数据
因为func函数里的array是形参,而main函数里的array是实参,只改变形参是不会改变实参的,所有输出结果还是原来数组里的元素
4.数组练习
(1)数组转字符串
import java.util.Arrays
int[] arr={1,2,3,4,5,6};
String newarr=Arrays.toString(arr);
System.out.println(newarr);
输出结果:[1,2,3,4,5,6]
Arrays.toString(数组名) 是一个专门用来把数组转换成字符串的函数
Java中提供了java.util,Arrays包,因此在使用这个函数之前,需要在最开头写 import java.util.Arrays
(2)数组排序(冒泡排序)
在写冒泡排序之前,先介绍一种即方便又简便的排序方法,那就是使用**Arrays.sort(数组名)**函数进行排序
public static void main(String[] args){
int[] array={100,12,34,28,93};
System.out.println(Arrays.toString(array));
Arrays.sort(array);
System.out.println(Arrays.toString(array));
}
Arrays.sort(array);就是java自带的一种方便的排序函数,以上输出就是按顺序排序的结果
拓展:Arrays.sort(array,0,2);这个的意思是对array这个数组的下标[0,2)区间进行排序,也就是只对第一个和第二个元素进行排序,注意:0,2 是左闭右开的
冒泡排序:
对于冒泡排序的原理在c语言指针这篇博客里讲到了,如果需要了解,可以去看看我的那篇博客,那么下面直接写代码和对代码进行分析
public static void main(string[] args){
int[] arr={9,10,7,3,4};
bubblesort(arr);
System.out.println(Arrays.toString(arr))
}
public static void bubblesort(int[] arr){
for(int i=0;i<arr.length-1;i++){
for(int j=1;j<=arr.length-i-1;j++){
if(arr[j-1]>arr[j]){
int tmp=arr[j-1];
arr[j-1]=arr[j];
arr[j]=tmp;
}
}
}
}
arr.length其实就是数组的元素个数(数组长度)
原理:就是每一趟把最大的数字放在最下面
(3)数组中元素的平均值
public static void main(String[] args){
int[] arr=new int[]{1,2,3,4,5,6};
System.out.println(avf(arr));
}
public static void arr(int[] arr){
int sum=0;
for(int x:arr){
sum += x;
}
return (double)sum/(double)arr.length;
}
这里也可以把for循环写成另一种好理解的形式
for(int i=0;i<arr.length;i++){
sum +=arr[i];
}
(4)数组拷贝
简单粗暴的拷贝:
public static void main(String[] args){
int array1[]={2,3,4,5,6};
int array2[]=new int[array1.length];
for(int i=0;i<array1.length;i++){
array2[i]=array1[i];
}
}
这种拷贝方法虽然很好理解,但是有点长,可以采用java自带的函数进行优化
使用拷贝函数: Arrays.copyOf(数组名,数组长度);
int[] array3=Arrays.copyOf(array1,srray1.length);
System.out.println(Arrays.toString(array3));
当然这个拷贝函数还有一个优点:可以给数组进行扩容
int[] array3=Arrays.copyOf(array1,array1.length*2);
在array1.length后面*2,就可以将拷贝的数组的元素个数翻2倍
拷贝某个范围
int[] array4=Array.copyOfRange(array1,2,4)
这里表示拷贝array1这个数组下标为[2,4)范围内的数据,形式为左闭右开
5.二维数组:
(1)基本格式(三种写法)
int[][] array1=new int[2][3];
int[][] array2=[][]{{1,2,3},{4,5,6}};
int[][] array3={{1,2,3},{4,5,6}};
注意:二维数组中行不可以省略,但是列可以省略
(2)二维数组的打印
int[][] array={{1,2,3},{4,5,6},{7,8,9}};
for(int row=0;row<array.length;row++){
for(int col=0;col<array[row].length;col++){
System.out.println(arr[row][col]);
}
}
这时会有疑问了,为什么row<array.length,为什么col<array[row].length,下面进行解析:
二维数组在java当中其实就是几个一维数组,因此在array.length中只会告诉我们,这个二维数组有几个一维数组,而array[row].length是在表明一维数组里有几个元素
当然还有一种更简洁高效的方法:使用java自带的函数Arrays.deepToString(数组名)
使用这个函数可以直接打印二维数组
它的写法和一维数组很像,在ToString前多加了一个deep
pyOf(array1,srray1.length);
System.out.println(Arrays.toString(array3));
当然这个拷贝函数还有一个优点:可以给数组进行扩容
```java
int[] array3=Arrays.copyOf(array1,array1.length*2);
在array1.length后面*2,就可以将拷贝的数组的元素个数翻2倍
拷贝某个范围
int[] array4=Array.copyOfRange(array1,2,4)
这里表示拷贝array1这个数组下标为[2,4)范围内的数据,形式为左闭右开
5.二维数组:
(1)基本格式(三种写法)
int[][] array1=new int[2][3];
int[][] array2=[][]{{1,2,3},{4,5,6}};
int[][] array3={{1,2,3},{4,5,6}};
注意:二维数组中行不可以省略,但是列可以省略
(2)二维数组的打印
int[][] array={{1,2,3},{4,5,6},{7,8,9}};
for(int row=0;row<array.length;row++){
for(int col=0;col<array[row].length;col++){
System.out.println(arr[row][col]);
}
}
这时会有疑问了,为什么row<array.length,为什么col<array[row].length,下面进行解析:
二维数组在java当中其实就是几个一维数组,因此在array.length中只会告诉我们,这个二维数组有几个一维数组,而array[row].length是在表明一维数组里有几个元素
当然还有一种更简洁高效的方法:使用java自带的函数Arrays.deepToString(数组名)
使用这个函数可以直接打印二维数组
它的写法和一维数组很像,在ToString前多加了一个deep