1.比较浮点型数据
public class Demo1 {
public static void main(String[] args) {
float a = 283535329879828949F;
float b = a+1;
int num = 10_0000_0000; //jdk7的新特性,允许数据较大的使用_来隔离
BigDecimal c = new BigDecimal(a);
BigDecimal d = new BigDecimal(b);
if (-1*1.0E-8<=Math.abs(a-b) && Math.abs(a-b)<=1*1.0E-8){
System.out.println("true");
//允许误差在精度范围之内可以用Math.abs函数,它提供有 int,long,float,double四种基本数据类型
}else {
System.out.println("false");
}
System.out.println(a==b); //true ,因为超出float精度
System.out.println(c==d); //false,比较浮点数,用BigDecimal类,不要用compareTo
}
}
2.java分为哪几种数据类型
有基本数据类型与引用数据类型,基本数据类型有byte,short,int,long,float,double,char,boolean,其余均为引用数据类型。Byte,Short,Integer,Long,String等这种大写开头的是类。
3.int溢出问题
public class Demo1 {
public static void main(String[] args) {
int number = 10_0000_0000;
int years = 200;
int total = number*years;
System.out.println(total); //1863462912,这属于int溢出问题,需要如下优化
//用数值范围更大以及更高级别的long转一下即可
long total2 = (long) number*years;
System.out.println(total2); //200000000000
//或者
long total3 = number*(long)years;
System.out.println(total3); //200000000000
}
}
4.Java变量
- 类变量:独立于方法之外的变量,用 static 修饰,类变量,是不用新建实例,直接通过类来调用的变量。特点是用static修饰。所以它们还有个响当当的名字,叫静态变量,静态方法。
- 局部变量:类的方法中的变量。
- 实例变量(全局变量):独立于方法之外的变量,不过没有 static 修饰。
public class Demo2 {
static int a = 0; //类变量,静态变量
String hello = "Hello World"; //实例变量
String name;
//实例变量,如果不初始化一个值,则基本数据类型默认为0/0.0,boolean默认为false,其余为null
int age; //实例变量
public void method(){
int i =0; // 局部变量,必须声明和初始化值
}
public static void main(String[] args) {
Demo2 demo2 = new Demo2();
System.out.println(demo2.hello); //Hello World
System.out.println(demo2.name); //null
System.out.println(demo2.age); //0
}
}
6.Java的final关键字分析
String类就是一个final类,在Java中,final关键字可以用来修饰类、方法和变量(包括成员变量和局部变量)。
用于修饰类、属性和方法;
- 被final修饰的类不可以被继承
- 被final修饰的方法不可以被重写
- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的
1)修饰类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。否则会提示如下:无法从final继承。
在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
final修饰的类依旧可以实例化被引用。
public class Demo5 {
public static void main(String[] args) {
Test t = new Test("小明");
System.out.println(t.getName());
}
}
final class Test{
private String name;
public Test(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2)修饰变量(常量)
常量:初始化后不能再改变值,也就是不会变动的值。所谓常量可以理解为一种特殊的变量,它的值被设定后在程序运行过程中不允许被改变。常量名一般使用大写字符开头,而且用final修饰;
例如:final double PI=3.14;
static与final都是修饰符,用的是否不分先后顺序,例如final static PI=3.14或者static final PI=3.14都可以。
对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
public class Demo3 {
public final static int count2 = 0; //常量
public static void main(String[] args){
Demo3 counterA = new Demo3();
int a1 = counterA.count2+1;
System.out.println(a1); //1
counterA.count2++;
//提示:Cannot assign a value to final variable,即无法为最终变量赋值
counterA.count2+=1; //提示同上,这样写是错的,代码过不去
int b1 =counterA.count2+4;
System.out.println(b1); //4
//final修饰的常量被引用时不会改变
final Object obj = new Object();
obj = new Object();
//报错提示:Cannot assign a value to final variable,即无法为最终变量赋值
}
}
7.if选择结构
无论是if else,还是if,else if,else,或者嵌套if,在同一级下,一旦满足其中一个为true,则跳过其余if而不去执行。
8.switch穿透现象
public class Demo4 {
public static void main(String[] args) {
char grade = 'C';
String grade = "字符串"; //jdk7后switch开始支持字符串
switch (grade){
case 'A':
System.out.println("优秀");
break;
case 'B':
System.out.println("良好");
//如果不加break,下方会一个一个全部执行并输出,这个就叫switch穿透现象
case 'C':
System.out.println("及格");
case 'D':
System.out.println("不及格");
default:
System.out.println("很差");
}
}
}
字符的本质仍是数字,所以需要用反编译来验证一下,修改Demo4如下,
public class Demo4 {
public static void main(String[] args) {
String grade = "C";
switch (grade){
case "A":
System.out.println("优秀");
break;
case "B":
System.out.println("良好");
break;
case "C":
System.out.println("及格");
break;
default:
System.out.println("很差");
}
}
}
idea可以直接查看class文件,直接把该class文件复制到项目里是无法复制的,所以得从文件系统里手动copy到项目中,这个class文件在src同等级下的out文件夹里面,
然后在用idea打开,代码如下,是通过把这个grade实例变量通过hashCode函数生成一个值然后再去case里匹配,中文或者字母都有一个唯一的hashcode值,这是都是通过hash值来比较的。
public class Demo4 {
public Demo4() { }
public static void main(String[] args) {
String grade = "C";
byte var3 = -1;
switch(grade.hashCode()) {
case 65:
if (grade.equals("A")) {
var3 = 0;
}
break;
case 66:
if (grade.equals("B")) {
var3 = 1;
}
break;
case 67:
if (grade.equals("C")) {
var3 = 2;
}
}
switch(var3) {
case 0:
System.out.println("优秀");
break;
case 1:
System.out.println("良好");
break;
case 2:
System.out.println("及格");
break;
default:
System.out.println("很差");
}
}
}
9.while与do--while区别
while先判断后执行,do--while是先执行后判断,而且总是保证循环体会被至少执行一次,这是主要差别。
public class Demo5 {
public static void main(String[] args) {
int a = 0;
while(a<0){
System.out.println(a);
a++;
}
System.out.println("========================");
do{
System.out.println(a);
a++;
}while (a<0);
}
}
输出结果为:
========================
0
所以do--while与while在条件都为false的情况下,do--while会至少执行一次。
10.打印九九乘法表
public class Demo6 {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j+"X"+i+"="+i*j+" ");
}
System.out.println();
}
}
}
11.分别输出1-100之间的偶数和与奇数和
public class Demo6 {
public static void main(String[] args) {
int ounum=0;
int jinum=0;
for (int i = 0; i <= 100; i++) {
if(i%2==0){ //偶数
ounum+=i;
}else{
jinum+=i;
}
}
System.out.println("偶数为:"+ounum);
System.out.println("奇数为:"+jinum);
}
}
12.输出1-1000能被5整除的数并且要求一行显示三个
public class Demo6 {
public static void main(String[] args) {
for (int i = 0; i <= 1000; i++) {
if(i%5==0){
System.out.print(i+" ");
}
if(i==0){
System.out.println();
}
}
}
}
13.增强for循环
public class Demo6 {
public static void main(String[] args) {
int[] numbers = {10,20,30,40,50};
for (int x : numbers){ //增强for循环
System.out.println(x);
}
System.out.println("=============="); //或者
for (int y=0;y<numbers.length;y++){
System.out.println(numbers[y]);
}
}
}
14.break与continue用法以及解析
1)break在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句,也在switch使用。
public class Demo6 {
public static void main(String[] args) {
int i = 0;
while (i<100){
i++;
System.out.println(i);
if(i==30){
break;
}
}
System.out.println("break不会中止程序的运行,只是跳出循环,此处依然会执行");
}
}
2)continue语句用在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。
public class Demo6 {
public static void main(String[] args) {
int i = 0;
while (i<=100){
i++;
if(i==0){
System.out.println();
continue;
//当i为10的倍数时跳出此次循环,只是此次不输出,下一次循环继续,不会退出整个大循环
}
System.out.println(i);
}
}
}
15.输出三角形,有点绕,理解思维即可
public class Demo6 {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
for (int j = 5; j >= i; j--) {
System.out.print(" ");
}
for (int j = 0; j <=i; j++) {
System.out.print("*");
}
for (int j = 0; j < i; j++) {
System.out.print("*");
}
System.out.println();
}
}
}
16.类和对象的区别
面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类和对象。其中,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。接下来通过一个图例来抽象描述类与对象的关系,如下图所示。
在上图中,可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系。类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实中的个体,它是类的实例。从上图中可以明显看出对象是根据类创建的,并且一个类可以对应多个对象,接下来分别讲解什么是类和对象。
17.Java方法
调用方法:对象名.方法名(实参列表)
设计方法原则:方法的本意是功能块,就是实现某个功能的语句块的集合。设计方法的时候最后保持方法的原子性,就是一个方法只完成一个功能,这样有利于后期的扩展。
public class Demo6 {
//java的main方法是被虚拟机调用的,java中只有值传递,没有引用传递
public static void main(String[] args) {
//实际参数:实际调用传递给某方法的参数,当方法返回一个值的时候,
//方法调用通常被当作一个值来传递给某个对象;
int c = add(1,2);
System.out.println(c);
}
//形式参数,用来定义作用的
//修饰符为public static,返回类型为int,方法名为add
public static int add(int a,int b){
return a+b; //return有终止方法的作用
}
}
18.Java方法重载
重载就是在一个类中有相同的函数名称但形参不同的函数。
方法的重载的规则:
- 方法名称必须相同。
- 参数列表必须不同(个数不同,类型不同或者排列顺序不同即可)
- 方法的返回类型可以相同也可以不同
- 仅仅返回类型不同不足以成为方法的重载。
jvm实现原理:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
public class Demo6 {
public static void main(String[] args) {
int c = add(1,2);
double d = add(1,2);
double e = add(1.0,2.0);
System.out.println(c); //3
System.out.println(d); //3.0
System.out.println(e); //-1.0
} //形式参数,用来定义作用的
public static int add(int a,int b){
return a+b;
}
public static double add(double a,double b){
return a-b;
}
}
19.Java可变参数
Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项。当可变参数个数多余一个时,必将有一个不是最后一项,所以只支持有一个可变参数。因为参数个数不定,所以当其后边还有相同类型参数时,java无法区分传入的参数属于前一个可变参数还是后边的参数,所以只能让可变参数位于最后一项。
可变参数的特点:
- 只能出现在参数列表的最后;
- 位于变量类型和变量名之间,前后有无空格都可以;
- 调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中一数组的形式访问可变参数。
public class Demo6 {
public static void main(String [] args){
System.out.println(add(2,3)); //5
System.out.println(add(2,3,5)); //10
}
public static int add(int x,int ...args){
//很多的源码里会这样写
int sum=x;
for(int i=0;i<args.length;i++){
sum+=args[i];
}
return sum;
}
}
20.Java递归
草稿
尽量避免使用递归,可以了解其思想,因为容易发生栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,尾递归是指,在函数返回的时候,调用自身本身,并且,return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
21.Java数组定义
- 数组是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
- 数组的元素是通过索引访问的,数组索引从0开始,声明一个数组首选dataType[] array而不是dataType array[]
public class Demo {
public static void main(String [] args) {
int[] nums; //声明一个数组
nums = new int[3]; //创建一个大小为3的数组
//int nums = new int[3]; //或者如此写,动态初始化
//int[] a = {1,2,3}; /静态初始化
nums[0] = 0; //给数组元素赋值
nums[1] = 1;
nums[2] = 2;
//System.out.println(nums[3]);
//提示:java.lang.ArrayIndexOutOfBoundsException: 3,发生数组越界
int sum=0;
for (int i = 0; i < nums.length; i++) {
//这里要注意不能等于,否则发生下标越界
sum+=nums[i];
}
System.out.println("总数为:"+sum);
int[][] array = {{1,2},{2,3},{3,4}};
System.out.println(array.length); //3
System.out.println(array.length);
}
}
数组三种初始化:
- 静态初始化: int[] a = {1,2,3}; Man[] mans={new Man(1,1),new Man(2,2)};
- 动态初始化:int[] a = new int[2]; a[0]=1;a[1]=2;
- 数组的默认初始化:数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化,比如上方a[1]初始化值为0;
数组四个基本特点:
- 其长度是确定的,数组一旦创建,它的大小就是不可以改变的。
- 其元素必须是相同类型,不允许出现混合类型。
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
- 数组变量属于引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
小结:
- 数组是相同数据类型(数据类型可以为任意类型)的有序集合
- 数组也是对象。数组元素相当于对象的成员变量
- 数组长度的是确定的,不可变的。如果越界,则报:ArrayIndexOutofBounds
22.Java多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
public class Demo {
public static void main(String [] args) {
int[][] array = {{1,2,3},{2,3},{3,4},{4,5,6,7}};
//此为二维数组,多维数组继续嵌套,套娃
System.out.println(array.length); //4
System.out.println(array[0]);
//输出内容为[I@4554617c,这是该数组元素的hashcode。要输出具体的内容如下覆盖toString方法
System.out.println(Arrays.toString(array[0])); //[1, 2, 3]
System.out.println(array[0].length); //3
System.out.println(array[0][0]); //1
}
}
23.稀疏数组
同二维数组一样,保存的是原矩阵某个不为0的元素的坐标位置以及值,固定多行3列。