6

Java学习笔记01 - JavaSE基础

 2 years ago
source link: https://segmentfault.com/a/1190000040957830
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

java https://c.runoob.com/compile/10

在线编写运行 Java 8 https://www.tutorialspoint.co...

SQL 在线运行 https://www.bejson.com/runcod...

Java牛客题库 https://www.nowcoder.com/inte...

JDK, JRE, JVM

  • JDK : Java Development Kit
  • JRE : Java Runtime Enviroment
  • JVM : Java Virtual Machine

输出Hello Wolrd

vim Hello.java

public class Hello{
    public static void main(String[] args){
        System.out.print("Hello World!");
    }
}

javac Hello.java

java Hello

Hello World!

Java程序运行机制

  • 程序运行机制:

    源文件(*.java) => Java编译器 => 字节码(.class)

    => JVM ( 类装载器 =>字节码校验器 => 解释器 )

    => 操作系统平台

File => New => Project… => Empty Project

File => Project Structure => Project => Project SDK (1.8.0) => Project language level (8) => OK

1.注释,标识符,关键字

//单行注释
/* 多行注释 */
/**
  * 文档注释
  * @Author itxiaoma
  */

类名,变量名,方法名都称为标识符

  • 标识符以字母,美元($),下划线(_)开始
  • 首字母后可以是字母,美元($),下划线(_),数字的组合
  • 不能使用关键字作为变量名,方法名
  • 大小写敏感
关键字(50+)

avator

2.数据类型

强类型语言:变量使用必须严格符合规定,所有变量都必须先定义后才能使用

Java数据类型
  1. 基本类型:(8大基本类型)

        1. byte:1个字节(-128~127)
        2. short:2个字节(-32768~32767)
        3. int:4个字节(-2147483648~2147483647)21亿+
        4. long:8个字节(例:long num=40L;)
        1. float:4个字节(例:float num=40F;)
        2. double:8个字节
      1. 字符串char:2个字节
    1. boolean:1位,true/false
  1. 引用类型:类,接口,数组

注1:String不是数据类型,是类

注2:1bit表示1位;(bit是计算机内部数据存储的最小单位)

​ 1Byte表示1个字节,1B=8b;

​ 1KB = 1024B;

​ 1MB = 1024KB;

​ 1GB = 1024MB;

​ 1TB = 1024GB;

Java数据类型的常见问题
  1. int a = 10;
    int b = 010;//八进制
    int c = 0x10;//十六进制
  2. 浮点型扩展

    float f = 0.1f;
    double d = 1.0/10;
    System.out.println(f==d);//false
    
    float d1 = 123123123123f;
    float d2 = d1 + 1;
    System.out.println(d1==d2);//true
    
    //float 有限 离散 舍入误差 接近但不等于
    //不要用浮点数进行比较
    //数学工具类BigDecimal
  3. 字符类扩展

    char a = 'a';
    System.out.println((int)a);//97
    char a1 = '\u0061';
    System.out.println(a1);//a
    //所有的字符本质还是数字
    
    转义字符:
    \t 制表符
    \n 换行
    ...

3.类型转换

运算中,不同类型的数据会先转换位同一类型,再进行计算

优先级:低 ==> 高

byte,short,char => int => long => float => double

自动转化:低 => 高

强制转换: 高 => 低 (类型)变量名

  1. 不能对布尔值进行转换
  2. 不能把对象类型转为不相干的类型
  3. 高容量转低容量,会有内存溢出或精度问题

注2:JDK7的新特性,数字间可以用下划线分割(1000 = 1_000)

4.变量、常量、作用域

int a = 1;
常量 - final

常量:初始化后不能改变,一般为大写

static final double PI = 3.14;
public class Hello {
    //类变量:static
    static int a = 1;
    //实例变量:属于对象,不需要初始化(会自动初始化为类型默认值)
    //布尔值默认false,除基本类型以外其他变量都是null
    String b;
    public static void main(String[] args) {
        System.out.println(a);

        int c = 3;//局部变量:必须声明和初始化
        System.out.println(c);

        Hello obj = new Hello();
        System.out.println(obj.b);//null
    }
}
命名规则:
  1. 类变量,局部变量,方法名:驼峰(首字母小写)
  2. 常量:大写 + 下划线
  3. 类型:驼峰(首字母大写)

5.基本运算符

  1. 算术运算符:+, -, *, /, %, ++, --
  2. 赋值运算符:=
  3. 关系运算符:>, <, >=, <=, ==, !=, instanceof
  4. 逻辑运算符:&&,||,!
  5. 位运算符:&, |, ^, ~, >>, << , >>>
  6. 条件运算符:? :
  7. 扩展赋值运算符:+=, -=, *= ,/=
long a = 123L;
int b = 123;
short c = 10;
byte d = 8;
System.out.println(a+d);//long
System.out.println(b+c);//int
System.out.println(c+d);//int
//结论:有long类型时转long,否则转int

幂运算:2^3

double pow = Math.pow(2, 3);
System.out.println(pow);//8.0
<< 乘2 
>> 除2

6.包机制

包的本质就是文件夹

  1. 包机制是为了更好地组织类,用于区别类名的命名空间
  2. 一般用公司名倒置作为报名 pakage com.baidu.www;
  3. 使用import导入包(import 包名.* 表示导入包下所有类)

7.JavaDoc生成文档

/**
 * @author 作者
 * @version 版本
 * @since 需要最早使用的jdk版本
 * @param 参数
 * @return 返回值
 * @throws 异常抛出
 */
javadoc -encoding UTF-8 -charset UTF-8 Demo.java

1.用户交互Scanner (Java5新特性)

import java.util.Scanner;

public class Demo {
    public static void main(String[] args) {
        //创建扫描器对象,用于接收键盘数据
        Scanner s = new Scanner(System.in);
        //判断用户输入
        if(s.hasNextLine()){
            String str = s.nextLine();
            System.out.println(str);
        }
        //IO流的类会一直占用内存,用完需要关闭
        s.close();
    }
}
//next()以空格为结束符,nextLine()以回车为结束符

计算多个数字的总和与平均数,非数字结束

Scanner s = new Scanner(System.in);
double sum = 0;
int num = 0;
while(s.hasNextDouble()){
    double x = s.nextDouble();
    sum += x;
    num++;
}
System.out.println("和是:" + sum);
System.out.println("平均值是" + (sum/num));
s.close();

2.九九乘法表

/*
1*1=1    
2*1=2    2*2=4    
3*1=3    3*2=6    3*3=9    
4*1=4    4*2=8    4*3=12    4*4=16    
5*1=5    5*2=10    5*3=15    5*4=20    5*5=25    
6*1=6    6*2=12    6*3=18    6*4=24    6*5=30    6*6=36    
7*1=7    7*2=14    7*3=21    7*4=28    7*5=35    7*6=42    7*7=49    
8*1=8    8*2=16    8*3=24    8*4=32    8*5=40    8*6=48    8*7=56    8*8=64    
9*1=9    9*2=18    9*3=27    9*4=36    9*5=45    9*6=54    9*7=63    9*8=72    9*9=81    
*/
for (int m = 1; m <= 9; m++) {
    for (int n = 1; n <= m; n++) {
        System.out.print(m + "*" + n + "=" + (m * n) + "\t");
    }
    System.out.println();
}
//System.out.print 不换行输出

3.增强for循环(JDK1.5新特性)

int[] numbers = {1, 2, 3, 4, 5};
for (int x : numbers) {
     System.out.println(x);
}

4.label

打印101 - 150间的所有质数

outer:for (int i = 101; i <= 150; i++) {
    for (int j = 2; j < i / 2; j++) {
        if (i % j == 0) {
            continue outer;
        }
    }
    System.out.println(i);
}

Java方法

方法是用来完成特定功能的代码片段,由方法名和方法体组成

方法名:修饰符 返回值类型 方法名 (参数类型 参数名){}

方法体:return 返回值;

参数类型:实参,形参

注:java都是值传递,没有引用传递

1.方法的重载

重载就是在一个类中,有相同的函数名称,但形参不同的函数

方法重载规则:

  1. 方法名称必须相同
  2. 参数列表必须不同(个数,类型,参数顺序不同)
  3. 返回类型可相同可不同

2.命令行传参

程序运行时传递参数,可以通过main方法传递

public static void main(String[] args) {
    for (int i = 0; i < args.length; i++) {
        System.out.println(args[i]);
    }
}

3.可变参数(JDK1.5新特性)

public static void main(String[] args) {
    test(1,2,3);
}
public static void test(int... i){
    System.out.println(i[0]);
    System.out.println(i[1]);
    System.out.println(i[2]);
}

递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。

递归体:什么时候需要调用自身方法。

Java数组

数组是相同类型数据的有序集合

dataType[] arrayRefVar = new dataType[size];

int nums[] = new int[10];
//二维数组
int[][] n = new int[2][2];
int[][] n = {{1,2},{3,4}} 
  1. 长度是确定的,一旦创建,长度不可变
  2. 元素类型必须相同
  3. 数组对象本身在堆中(数组是引用类型,可看做对象,数组元素相当于对象的成员变量,Java的对象在堆中)
java内存
存放new的对象和数组
可以被所有线程共享,不会存放别的对象引用
存放基本变量类型,包含具体数值
引用对象的变量,存放引用在堆中的地址
可以被所有线程共享
包含所有calss和static变量
//1.声明数组
int[] nums;//在栈中
//2.创建数组
nums = new int[10];//在堆中

三种初始化状态

//静态初始化
int[] a = {1, 2, 3};
Man[] mans = {new Man(1),new Man(2)}

//动态初始化(包含默认初始化)
int[] b = new int[10];//默认分配10个0
b[0] = 10;

注:数组是引用类型,数组元素相当于类的实例变量,数组创建时分配空间,数组元素也会按默认值初始化。

数组工具类java.util.Arrays

打印数组元素Arrays.toString(a);数组填充Arrays.fill(a, 0 , 1, 0);数组下标0-1的元素用0填充数组排序Arrays.sort(a); 比较数组equals 查找数组元素binarySearch对排序好的数组进行二分法查找
  1. 共有八大排序
  2. 时间复杂度为O(n2)

当一个数组中大部分元素为0或值相同时,可以使用稀疏数组保存

处理方式:

1.记录数组行列数,不同值数

2.把不同值的元素行列信息,元素值记录在小规模数组中

/*
稀疏数组
1    2    1
2    3    2
还原数组
0    0    0    0    0    0    0    0    0    0    0    
0    0    1    0    0    0    0    0    0    0    0    
0    0    0    2    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
0    0    0    0    0    0    0    0    0    0    0    
*/
public class Demo {
    public static void main(String[] args) {
        int[][] array1 = new int[11][11];
        array1[1][2] = 1;
        array1[2][3] = 2;
        int sum = 0;
        for (int i = 0; i < 11; i++) {
            for (int j = 0; j < 11; j++) {
                if (array1[i][j] != 0) {
                    sum++;
                }
            }
        }
        int[][] array2 = new int[sum + 1][3];
        array2[0][0] = 11;
        array2[0][1] = 11;
        array2[0][2] = sum;
        int count = 0;
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                if (array1[i][j] != 0) {
                    count++;
                    array2[count][0] = i;
                    array2[count][1] = j;
                    array2[count][2] = array1[i][j];
                }
            }
        }
        System.out.println("稀疏数组");
        for (int j = 1; j < array2.length; j++) {
            System.out.println(array2[j][0] + "\t" + array2[j][1] + "\t" + array2[j][2]);
        }
        System.out.println("还原数组");
        int[][] array3 = new int[array2[0][0]][array2[0][1]];
        for (int j = 1; j < array2.length; j++) {
            array3[array2[j][0]][array2[j][1]] = array2[j][2];
        }
        for (int[] ints : array3) {
            for (int num : ints) {
                System.out.print(num + "\t");
            }
            System.out.println();
        }
    }
}

以类的方式组织代码。以对象组织(封装)数据

三大特性:封装,继承,多态

1.创建类与对象

一个项目应该只存在一个main方法

使用new创建对象时,除了分配内存空间,还会给创建好的对象进行默认初始化,及调用类中的构造器。

com/oop/demo/Application.java

package com.oop.demo;
public class Application {
    public static void main(String[] args) {
        //类:抽象的,实例化后会返回一个自己的对象
        Student xiaoming = new Student();
        Student xiaohong = new Student();
        xiaoming.name = "小明";
        xiaoming.age = 20;
        xiaohong.name = "小红";
        xiaohong.age = 21;
        System.out.println("姓名:" + xiaoming.name + "\t年龄:" + xiaoming.age);
        xiaoming.study();
        System.out.println("姓名:" + xiaohong.name + "\t年龄:" + xiaohong.age);
        xiaohong.study();
    }
}

com/oop/demo/Student.java

package com.oop.demo;
public class Student {
    //属性
    String name;
    int age;
    //方法
    public void study() {
        System.out.println(this.name + "在学习");
    }
}
构造器(构造方法)
  1. 必须和类名相同
  2. 必须没有返回类型(不能写void)
  3. 一旦定义了有参数的构造器,new对象时想不传参数,就必须写一个无参数构造器
public class Student {
    //属性
    String name;
    int age;
    //无参(默认)构造器
    public Student(){
        
    }
    //有参
    public Student(String name){
        this.name = name;
    }
    public Student(String name,int age){
        this.name = name;
        this.age = age;
    } 
}

创建对象内存分析

public class Application {
    public static void main(String[] args) {
        //类:抽象的,实例化后会返回一个自己的对象
        Student xiaoming = new Student();
        Student xiaohong = new Student();
        xiaoming.name = "小明";
        xiaoming.age = 20;
        xiaohong.name = "小红";
        xiaohong.age = 21;
        System.out.println("姓名:" + xiaoming.name + "\t年龄:" + xiaoming.age);
        xiaoming.study();
        System.out.println("姓名:" + xiaohong.name + "\t年龄:" + xiaohong.age);
        xiaohong.study();
    }
}

方法区也在堆中;

静态方法区和类一起加载,所以静态方法可以直接调用,不需要实例化

  1. 加载Application和Student类信息到方法区
  2. 加载main()方法到栈中
  3. 加载xiaoming和xiaohong引用变量名到栈中
  4. 加载Student xiaoming = new Student();和Student xiaohong = new Student();实例到堆中
  5. xiaoming和xiaohong调用方法区的study方法

注:基本类型外的变量都是引用类型,是通过引用来操作的;引用名在栈中,指向对象实体在堆中的地址。

禁止直接访问一个对象中数据的实际表示,应通过接口操作来访问。

属性私有(private),get/set

public class Student {
    private String name;
    private int age;
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getAge() {
        return age;
    }
}

继承extends

继承的本质是对某一批类的抽象,从而实现更好的建模;

继承是类之间的关系,子类继承(extends)父类的全部public方法;

私有的属性和方法无法被继承

  1. Java中只有单继承,没有多继承 (一个子类只能有一个父类)
  2. Java中所有类,都默认直接或间接继承Object类

Super

  1. super调用父类的构造方法,必须在构造方法的第一行
  2. super只能出现在子类的方法或构造方法中
  3. super和this不能同时在构造方法中调用(都需要在第一行)
super和this的区别
thissuper代表对象不同调用者本身的对象父类对象的引用使用前提不同没有继承也能使用只能在有继承时使用调用构造方法不同调用本类的构造方法调用父类的构造方法

com/oop/demo/Application.java

package com.oop.demo;

public class Application {
    public static void main(String[] args) {
        Student xiaoming = new Student();
        xiaoming.test1();
        //Person无参构造
        //Student无参构造
        //Student
        //Student
        //Person
    }
}

com/oop/demo/Person.java

package com.oop.demo;

public class Person {
    public Person() {
        System.out.println("Person无参构造");
    }
    public void print(){
        System.out.println("Person");
    }
}

com/oop/demo/Student.java

package com.oop.demo;

public class Student extends Person{
    public Student() {
        //隐藏代码:调用了父类的无参构造super();
        //super();
        System.out.println("Student无参构造");
    }
    public void print(){
        System.out.println("Student");
    }
    public void test1(){
        print();
        this.print();
        super.print();
    }
}

方法重写@Override

子类的方法和父类必须要一致,方法体不同

重写都是方法的重写,和属性无关

静态方法不能被重写 !

  1. 方法名,参数列表必须相同
  2. 修饰符范围可以扩大不能缩小
  3. 抛出异常范围可以缩小不能扩大
public class B {
    public static void test(){
        System.out.println("B=>test()");
    }
}
public class A extends B{
    public static void test(){
        System.out.println("A=>test()");
    }
}
public class Application {
    public static void main(String[] args) {
        //静态方法:方法调用只和左边定义的数据类型有关
        A a = new A();
        a.test();//A=>test()
        //父类的引用指向了子类
        B b = new A();
        b.test();//B=>test()
    }
}
public class B {
    public void test(){
        System.out.println("B=>test()");
    }
}
public class A extends B{
    @Override
    public void test() {
        System.out.println("A=>test()");
    }
}
public class Application {
    public static void main(String[] args) {
        A a = new A();
        a.test();//A=>test()
        B b = new A();
        b.test();//A=>test()
    }
}

同一方法根据发送对象不同,采用多种不同的行为方式;

一个对象的类型是确定的,但可以指向对象的引用类型有很多(可以是子类,父类,Object)

多态存在的条件:

  1. 有继承关系
  2. 子类重写父类方法
  3. 父类引用指向子类对象

注:多态是方法的多态,属性没有多态。

无法重写的方法
  1. static方法,属于类,不属于实例
  2. final 常量 (final修饰的类不能被继承)
  3. private方法
//子类能调用的方法都是自己的或继承父类的
A a = new A();
B b = new B();
//对象能执行哪些方法看左边的引用类型
//父类引用可以指向子类,但不能调用子类独有的方法
B c = new A();
a.test();//A=>test()
b.test();//B=>test()
//子类重写了父类方法,会执行子类的方法
c.test();//A=>test()

instanceof和类型转化

  1. 父类引用可以指向子类的对象,反过来不行
  2. 子类转换为父类称为向上转型,可能丢失自己本来的一些方法
  3. 父类转换为子类称为向下转型,需要强制转换
public class Application {
    public static void main(String[] args) {
        //子类特有方法go
        Student s = new Student();
        s.go();
        //向上转型,转型后无法再调用go方法
        Person p = s;
        //向下转型
        ((Student) p).go();
    }
}

static关键字

private static int age;
public class Application {
    private static void test(){
        System.out.println("Static Function");
    }
    public static void main(String[] args) {
        test();
    }
}
静态代码块
public class Person {
    {
        System.out.println("匿名代码块");
    }
    static {
        System.out.println("静态代码块");//只会在类加载时执行一次
    }
    public Person() {
        System.out.println("构造方法");
    }
    public static void main(String[] args) {
        Person p = new Person();
        //静态代码块
        //匿名代码块
        //构造方法
    }
}
静态导入包
import static java.lang.Math.random;
public class Person {
    public static void main(String[] args) {
        System.out.println(random());
    }
}

抽象类 abstract

//抽象类 (接口可以多继承)
abstract class Person {
    public abstract void doSomething();//抽象方法:只有方法名,没有方法体
}
  1. 抽象类不能new,只能靠子类实现
  2. 抽象方法必须在抽象类中,但抽象类可以包含普通方法

接口 interface

对对象的抽象,约束和实现分离:面向接口编程

  1. 接口不能被实例化,接口中没有构造方法
  2. 接口中所有方法都是抽象的(public abstract)
  3. 接口中只有常量(public static final)
  4. 类通过implements实现接口,一个类可以实现多个接口,实现多继承
  5. 实现接口的类,必须重写接口中所有方法
public interface UserService {
    void userTest1();
    void userTest2();
}
public interface TimeService {
    void time1();
    void time2();
}
public class UserTime implements UserService,TimeService{
    @Override
    public void userTest1() {
    }
    @Override
    public void userTest2() {
    }
    @Override
    public void time1() {
    }
    @Override
    public void time2() {
    }
}

匿名对象:不将实例保存到变量(栈)中,只在堆内存中使用对象

public class Application {
    public static void main(String[] args) {
        new Apple().eat();
    }
}
class Apple{
    public void eat(){
        System.out.println("吃苹果");
    }
}

匿名内部类

public interface UserService {
    void userTest1();
    void userTest2();
}
public class Application {
    UserService u = new UserService() {
        @Override
        public void userTest1() {
        }
        @Override
        public void userTest2() {
        }
    };
}

异常Error Exception

Error

Error类对象由JVM生成并抛出,大多数错误与操作无关,发生错误时JVM一般会终止线程;

如内存溢出(OutOfMemeryError),栈溢出,类定义错误(NoClassDefFoundError),链接错误(LinkageError)

Exception

异常通常由逻辑错误引起,应尽量避免

  1. 非运行时异常(IO异常...)
  2. 运行时异常(RuntimeException)

注:Error通常是致命性错误,程序无法处理;Exception通常可以且应该尽可能的处理。

异常处理机制

  1. try 监控区域 (必要)
  2. catch 捕获异常 (必要)
  3. finally 最终处理 (释放占用资源)
  4. throw 抛出异常(一般在方法中使用 )
  5. throws

注:捕获多个异常需要从小到大XXXException < XXXException < Throwable

public class Application {
    public static void main(String[] args) {
        int a = 1;
        int b = 0;
        try{
            if(b == 0){
                throw new ArithmeticException();
            }
            System.out.println(a/b);
        }catch (ArithmeticException e){
            e.printStackTrace();//打印错误的栈信息
        }catch (Exception e){
            
        }catch (Throwable e){
            
        }finally {
            
        }
    }
}

自定义异常

用户自定义异常类,只需要继承Exception类即可

public class MyException extends Exception {
    String msg;

    public MyException(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "MyException{" + msg + "}";
    }
}
public class Application {
    static void test(String msg) throws MyException{
        throw new MyException(msg);
    }
    public static void main(String[] args) {
        try{
            test("test");
        }catch (MyException e){
            System.out.println(e);//MyException{test}
        }
    }
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK