每天学一点
- JVM、JRE和JDK的区别
- 环境变量path和classpath的作用是什么?
- GC是什么?为什么要有GC?
- 一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
- 字面量
- 变量有什么用?为什么要定义变量?什么时候用?
- Java的数据类型有哪些?
- && 和 & 的区别,|| 和 | 的区别
- Char型变量中能不能存储一个中文汉字?为什么?
- ++i与i++的区别
- short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
- Java 中的final关键字有哪些用法?
- swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
- 跳转关键字
- 数组
- 方法
- 两数之和Ⅱ-输入有序数组
JVM、JRE和JDK的区别
JVM(Java Virtual Machine):Java虚拟机
- Java虚拟机是一个可以执行Java字节码的虚拟机进程
- Java源文件被编译成能被Java虚拟机执行的字节码文件
- 用于保证Java的跨平台的特性
- 补充:Java中的所有类都必须装载到JVM中才能运行。Java类的装载主要通过类加载器才能完成。类加载器:将class文件从硬盘读取到内存中
JRE(Java Runtime Environment) Java运行环境
- Java的运行环境,包括JVM+Java的核心类库
JDK(Java Development Kit) Java的开发工具
- Java的开发工具,包括JRE+开发工具
- 可以让开发者开发、编译、执行应用程序
环境变量path和classpath的作用是什么?
- Path是配置Windows 可执行文件的搜索路径,即扩展名为.exe的程序文件所在目录,用于指定DOS窗口命令的路径
- 作用:记住程序的路径,方便在命令行窗口的任意目录驱动程序
- Classpath是配置class文件所在的目录,用于指定类搜索路径,JVM就是通过它来寻找该类的class类文件的
GC是什么?为什么要有GC?
- GC是垃圾收集的意思,垃圾回收可以有效地防止内存泄漏,有效的使用内存。
- 垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存推中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。
- Java提供GC功能可以自动检测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。
- 可以调用下面的方法之一:System.gc() 或 Runtime.getRuntime().gc(),但JVM可以屏蔽掉显示的垃圾回收调用。
一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
可以,但是一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。
- 内部类:有访问外部类成员的权限, 通常被称为内部类。
- 私有内部类:内部类可以使用 private 或 protected 来修饰,如果你不希望内部类被外部类访问可以使用 private 修饰符。
- 静态内部类可以使用 static 关键字定义,静态内部类我们不需要创建外部类来访问,可以直接访问它。
- class OuterClass { // 外部类
- // ...
- class NestedClass { // 嵌套类,或称为内部类
- // ...
- }
- }
字面量
- 目的:告诉程序员数据在程序中该怎么书写
- 分类:
- 整数、小数
- 字符:用单引号,里面只能一个字符
- 字符串:用双引号,里面内容随意
- 布尔值:false true
- 空值:null
变量有什么用?为什么要定义变量?什么时候用?
- 变量的作用:内存中的一块区域,里面用来存储数据,存储的数据可以变化
- 格式:数据类型 变量名称 = 初始值
- 为什么要定义变量:用来不断的存放同一类型的常量,并可以重复使用
- 赋值:从右往左执行
- 注意事项:
- 变量必须先声明才能使用
- 什么类型的变量只能存放什么类型的数据
- 变量从定义开始就有效,同一个有效范围内不能定义重名的变量
- 变量定义的时候可以没有初始值,但是使用前必须有初始值
- 变量在计算机中底层原理:
- 变量存储的数据时二进制形式
- 数据变二进制的规则:逢二进一
Java的数据类型有哪些?
- 作用:约束变量只能存储什么类型的数据,帮助定义出不同类型的变量
- 基本数据类型:byte short int long float double char Boolean
- byte:字节整型:1字节 -128-127
- short:短整型:2字节
- int :整型 默认 4字节
- long:长整型 8字节
- float: 单精度 4字节
- double:双精度 8字节
- char:字符型 2字节
- boolean:布尔型 1字节
注意事项:
随便写整数字面量默认int类型,相当于long类型后面加L
随便写小数字面量,默认double类型,相当于float类型后面加F
long j = 1000000000000L;
float f = 12.345F;
- 引用数据类型:类 接口 枚举 注解 数组
- 数据类型的相互转换
正向的过程: 从低字节向高字节可以自动转换 (Java中的自动类型提升 )
byte-> short-> int-> long-> float-> double
三种情况:
int -> float
long -> float
long -> double
特殊情况:char <-> int (相互转换)
package 基础;
class DataTypeDemo {
public static void main(String[] args) {
//定义变量的格式:
//数据类型 变量名 = 初始化值;
//定义一个字节变量
byte b = 10;
System.out.println(10);//10
System.out.println(b);//10
//定义一个短整型变量
short s = 100;
System.out.println(s);//100
//定义一个整型变量
int i = 1000;
System.out.println(i);//1000
//超过了int的范围
//int j = 1000000000000;
long j = 1000000000000L;//长整型后缀用L或者l标记。建议使用L。
//long j = 100L;
System.out.println(j);//1000000000000
//定义浮点数据变量
float f = 12.345F;//单精度浮点数用F或者f标记。建议使用F。
System.out.println(f);//12.345
//float f2 = (float) 12.3;
float f2 = 12.3F;
System.out.println(f2);//12.3
double d = 12.345;
System.out.println(d);//12.345
double e = 12.3;//12.3
System.out.println(e);
//定义字符变量
char ch = 'a';
System.out.println(ch);//a
//定义布尔变量
boolean flag = true;
System.out.println(flag);//true
}
}
&& 和 & 的区别,|| 和 | 的区别
- 与
- & 逻辑与:且的意思,必须前后都是true,结果才是true
- && 短路与:且的意思,必须前后都是true,结果才是true
- 区别:&& 如果大小前面时false后面不执行,直接返回结果,性能较好一点,用的更多一点
- 或
- | 逻辑或:或的意思,只要前后有一个是true,结果就是true
- || 短路或:或的意思,只要前后有一个是true,结果就是true
- 区别:|| 如果大小前面时true后面不执行,直接返回结果,性能较好一点,用的更多一点
补充:
!取反
^ 异或 前后一样返回false
package 基础;
/*
&&和&的区别? 同理||和|的区别?
A:最终结果一样。
B:&&具有短路效果。左边是false,右边不执行。
开发中常用的逻辑运算符:
&&,||,!
*/
class OperatorDemo3 {
public static void main(String[] args) {
int a = 3;
int b = 4;
int c = 5;
//&&双与
System.out.println((a > b) && (a > c)); //false && false = false
System.out.println((a > b) && (a < c)); //false && true = false
System.out.println((a < b) && (a > c)); //true && false = false
System.out.println((a < b) && (a < c)); //true && true = true
System.out.println("----------------");
int x = 3;
int y = 4;
//boolean b1 = ((x++ == 3) & (y++ == 4));
//System.out.println("x:"+x);//4
//System.out.println("y:"+y);//5
//System.out.println(b1);//true
//boolean b1 = ((x++ == 3) && (y++ == 4));
//System.out.println("x:"+x);//4
//System.out.println("y:"+y);//5
//System.out.println(b1);//true
//boolean b1 = ((++x == 3) & (y++ == 4));
//System.out.println("x:"+x);//4
//System.out.println("y:"+y);//5
//System.out.println(b1);//false
boolean b1 = ((++x == 3) && (y++ == 4));
System.out.println("x:"+x);//4
System.out.println("y:"+y);//4
System.out.println(b1);//false
}
}
Char型变量中能不能存储一个中文汉字?为什么?
- Char型bia能量是用来存储Unicode编码字符的,Unicode编码字符集包含了汉字,所以char型变量中可以存储汉字。只是,如果某个特殊的汉字没有被包含在Unicode编码字符集中,那么这个char型变量中就不能存储这个汉字。
- Unicode编码占用两个字节,所以char类型的变量也占用两个字节。
++i与i++的区别
就近原则:
- i++ 先赋值后自增,例如 a=i++,先赋值a=i,后自增i=i+1,所以结果是a=1
- ++i 先自增在赋值,例如 a=++i,先自增i=i+1,后赋值a=i,所以结果是a=2
package 基础;
/*
++,--运算符的使用:
单独使用:
放在操作数的前面和后面效果一样。(这种用法是我们比较常见的)
参与运算使用:
放在操作数的前面,先自增或者自减,然后再参与运算。
放在操作数的后面,先参与运算,再自增或者自减。
作用:就是对变量进行自增1或者自减1。
*/
class OperatorDemo2 {
public static void main(String[] args) {
//定义两个变量
int x = 3;
int y = 4;
//字符串的拼接,字符串在前面
//System.out.println("x:"+x);
//System.out.println("y:"+y);
System.out.println("x:"+x+",y:"+y);//3,4
//单独使用
//x++;
//y--;
++x;
--y;
//System.out.println(x);
System.out.println("x:"+x+",y:"+y);//4,3
//意外的类型,常量是不可以这样做的
//System.out.println(10++);
System.out.println("-------------------");
//参与运算使用
int a = 3;
int b = 4;
//int c = a++;
//int d = b--;
int c = ++a; //++放在操作数前面,先自增或者自减,然后再赋值
int d = --b;
System.out.println("a:"+a); //4, 4
System.out.println("b:"+b); //3, 3
System.out.println("c:"+c); //3, 4
System.out.println("d:"+d); //4, 3
}
}
short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?
- 对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。
- short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。
a += b 等价于: a = (a的类型)(a+b)
Java 中的final关键字有哪些用法?
- 修饰类:表示该类不能被继承,即不能有子类
- 修饰方法:表示方法不能被重写;
- 修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
补充
switch作用:根据表达式值来进行值匹配选择对应的分支执行
注意事项:不要忘记写break,否则会出现穿透现象
穿透性:switch没有写break,遇到case会继续往下走,知道遇到break才会跳出;适合多个值对应case块操作是相同的,可以穿透到一个位置集中处理,提高开发效率,降低代码重复
swtich可以作用在byte,short,int,char,枚举,String,Byte,Short,Integer,Character
从Java 7开始,expr还可以是字符串(String),但是长整型(long)在目前所有的版本中都是不可以的。
简单表述:
因为在switch表达式中,表达式只能是整数int(Integer)或者枚举常量;由于byte,short,char可以自动转换为int
package 基础;
/*
switch语句格式:
switch(表达式) {
case 值1:
语句体1;
break;
case 值2:
语句体2;
break;
...
default:
语句体n+1;
break;
}
格式的解释:
switch:表示这是switch选择结构
表达式:这个地方的取值是有限定的
byte,short,int,char
JDK5以后可以是枚举
JDK7以后可以是字符串
case:后面跟的是要和表达式进行比较的值
语句体:要执行的代码
break:表示中断,结束的意思,可以控制switch语句的结束。
default:当所有的值都和表达式不匹配的时候,就执行default控制的语句。其实它就相当于if语句的else。
if语句和switch语句的区别?
if语句:
A:针对结果是boolean类型的判断
B:针对一个范围的判断
C:针对几个常量值的判断
switch语句:
针对几个常量值的判断
实例:
byte可以作为switch的表达式吗? 可以
long可以作为switch的表达式吗? 不可以
String可以作为switch的表达式吗? jdk7以后可以
案例:
键盘录入一个数据,根据这个数据,我们输出对应的星期?
键盘录入1,对应输出星期一
键盘录入2,对应输出星期二
...
键盘录入7,对应输出星期日
分析:
1:键盘录入,用Scanner实现
2:判断我们既可以使用if语句,也可以使用我们要讲解的switch语句
注意:
A:遇到左大括号缩进一个tab的位置。
B:关联不是很大的语句间空行
*/
import java.util.Scanner;
class SwitchDemo {
public static void main(String[] args) {
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//控制键盘录入数据
System.out.println("请输入一个数据(1-7):");
int week = sc.nextInt(); //3
//switch判断语句
switch(week) {
case 1:
System.out.println("星期一");
break;
case 2:
System.out.println("星期二");
break;
case 3:
System.out.println("星期三");
break;
case 4:
System.out.println("星期四");
break;
case 5:
System.out.println("星期五");
break;
case 6:
System.out.println("星期六");
break;
case 7:
System.out.println("星期日");
break;
default:
System.out.println("你输入的数据有误");
break;
}
}
}
跳转关键字
- break:跳出并结束当前循环的执行,只能用于结束所在循环或者结束所在switch分支执行
- continue:跳出当前循环的当次执行,进入下一次循环,只能在循环中进行实现
数组
- 作用:一个容器,用于程序中存储一批同种类型的数据
- 定义:
- 静态初始化
- int [ ] num1=new int []{1,2,3};
- 特点:在定义数组时同时为数组确定了数据
- 使用场景:一旦确定了数据的具体值,使用这种方法批量存储数据
- 动态初始化
- int [] num2 =new int [3];
- 特点:一开始确定了数组的类型和长度,不确定具体的数据值
- 使用场景:适合做一开始不能确定具体数据的情况
- 元素存在默认值
- 静态初始化
- 数组内存图
- 方法区:放class文件
- 栈内存:运行的方法,main方法,定义的变量
- 堆内存:new出来的对象
方法
- 作用:封装一段代码的语法结构,可以被重复调用,提高代码的复用性
- 格式:
修饰符 返回值类型 方法名称(参数类型 参数名称,…){
方法体
return 返回值;
}
如果方法没有结果数据需要返回,返回值类型:void
方法的参数传递机制
Java中按值传递和引用传递区别
• 值传递(pass by value):在调用函数时,将实际参数复制一份传递到函数中,这样在函数中对参数进行修改,就不会影响到原来的实际参数;
• 引用传递(pass by reference):在调用函数时,将实际参数的地址直接传递到函数中。这样在函数中对参数进行的修改,就会影响到实际参数;
- 对于基本数据来说,在进行传递的时候,将数据的值复制了一份进行的传递,所以我们也比较好理解的这种值传递;
- 对于对象数据类型,因为该对象本身指向的是它在内存中的地址,所以方法调用的时候,实际上是创建的地址的副本,所以在方法中对其值进行改变的时候,他的地址没有变,值也就跟着改变了;而当你重新创建一个对象的时候,它指向的便是另一个对象的地址了。
Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。
两数之和Ⅱ-输入有序数组
给定一个已按照 升序排列 的整数数组 numbers
,请你从数组中找出两个数满足相加之和等于目标数 target
。
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
暴力法
使用双重for
循环,第一次for
循环每次选取一个数,第二次for
循环每次从剩余的数中选取一个数,然后计算两数之和,将其值与目标值比较
class Solution{
public int[] twoSum(int[] numbers,int target){
int[] result = new int[2];
for(int i=0;i<numbers.length;i++){
for(int j=i+1;j<numbers.length;j++){
if(numbers[i]+numbers[j]==target){
result[0]=i+1;
result[1]=j+1;
}
}
}
return result;
}
}
双指针
class Solution{
public int[] twoSum(int[] numbers,int target){
int[] result = new int[2];
//定义左侧指针left,指向数组中的第一个元素
int left = 0;
//定义右侧指针right,指向数组中最后一个元素
int right = numbers.length-1;
while(left < right){
//如果左侧指针与右侧指针所指向的元素和等于目标值,则返回结果
if(numbers[left]+numbers[right]==target){
result[0]=left+1;
result[1]=right+1;
return result;
}else if(numbers[left]+numbers[right]<target){
//如果左侧指针与右侧指针所指向的元素和小于目标值
//因为数组是升序排列的,为了让两数之和变大一些
//因此应将左侧指针向移动一位
left++;
}else if(numbers[left]+numbers[rught]>target){
//如果左侧指针与右侧指针所指向的元素和大于目标值
//因为数组是升序排列的,为了让两数之和变小一些
//因此应将右侧指针向左移动一位
right--;
}
}
return result;
}
}