学习视频地址:https://www.bilibili.com/video/BV12J41137hu
新建一个java文件(文件后缀名.java)
编写代码
public class Hello {
public static void main(String[] args) {
System.out.print("hello world!");
}
}
编译javac hello.java,会生成一个class文件
运行class文件,java hello
compile,完全编译。
操作系统、C、C++……
一点一点编译。
JavaScript、python……
Java既有编译型特征也有解释型特征
java中的注释有三种:
Java所有的组成部分都需要名字。类名、变量名记忆方法名都被称为标识符
标识符注意点
pubilc、class、static、void……
强类型语言
要求变量的使用要严格符合规定,所以所有变量都必须先定义后才能使用
弱类型语言
JavaScript
Java的数据类型分为两大类
基本类型(数值类型:整数、浮点、字符,boolean类型:占一位其值只有true和false两个)
//八大基本数据类型
//整数
int num1 = 10; //最常用 4个字节
byte num2 = 20; //1个字节
short num3 = 30; //2个字节
long num4 = 40L; //Long类型要在数字后面加一个L 8个字节
//小数:浮点数
float num5 = 50.1F; //float类型要在数字后面加个F 4个字节
double num6 = 3.14159263256236; //8个字节
//字符
char name = "吉"; //只能一个字符 2个字节
//字符串,String不是关键字,它是一个类
//布尔值 1位
boolean flag1 = true;
boolean flag2 = false;
//======================================
//整数拓展 进制 二进制0b 八进制0 十进制 十六进制0x
int i1 = 0b10; //二进制
int i2 = 010; //八进制
int i3 = 10; //十进制
int i4 = 0x10; //十六进制
//浮点数拓展 银行业务的表示?
//float double
float f = 0.1f; //0.1
double d = 1.0/10; //0.1
f==d; //false
float d1 = 31231312312f;
float d2 = d1 + 1;
d1==d2; //true
//最好完全使用浮点数进行比较
//字符拓展
char i1 = 'a';
char i2 = '吉';
System.out.print(i1); //a
System.out.print((int)i1); //97
System.out.print(i2); //吉
System.out.print((int)i2); //21513
//所有字符本质还是数字
//编码 Unicode
char i3 = '\u0061';
System.out.print(i3); //a
//转义字符
//\t 制表符
//\n 换行符
//……
System.out.print("Hello\tWorld");//Hello World
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = "hello";
String s4 = "hello";
System.out.print(s1==s2); //false 对象 从内存分析
System.out.print(s3==s4); //true
引用类型(类、接口、数组)
由于java是强类型语言,所以要进行有些运算的时候,需要用到类型转换。
运算中,不同类型的数据先转换为同一类型,然后进行运算。
int i = 128;
byte b = (byte)i; //内存溢出 byte最大值127
double c = i;
System.out.println(b); //-128
//强制转换 (类型)变量名 高->低
//自动转换 低->高
(int)23.3; //23
(int)-45.23; //-45
char c = 'a';
int d = c + 1; //98
(char)d; //b
注意点
操作比较大的数的时候,注意溢出问题
JDK新特性,数字之间可以用下划线分割
int money = 10_0000_0000;
int year = 20;
int total1 = money * year; //-1474…… 计算的时候溢出了
long total2 = money * year; //默认是int,转换之前就已经溢出了
long total3 = money * ((long)year); //先把一个数转换成long
Java是一种强类型语言,每个变量都必须声明类型。
Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域。
type varName [=value] [{,varName [=value]}];
数据类型 变量名 = 值;可以使用逗号隔开来声明多个同类型变量。
注意事项
变量作用域
public class Variable{
static int allClick=0; // 类变量
String str="hello world"; // 实例变量
public void method(){
int i=0; //局部变量 必须声明和初始化值
}
}
常量(Constant):初始化后不能再改变值!不会变动的值。
所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。
//final 常量名=值
final double PI = 3.14;
常量名一般使用大写字符。
Java语言支持如下运算符:
int a=3;
int b=a++; //执行完这行代码后,先给b赋值,再自增 b=3 a=4
int c=++a; //执行完这行代码后,先自增,再给c赋值 a=5 c=5
为了更好地组织类,java提供了包机制,用于区别类名的命名空间。
包的本质就是一个文件夹。
包语句的语法格式为:
package pkg1[. pkg2[. pkg3]]
一般利用公司域名倒置作为包名。
为了能够使用某一个包的成员,我们需要在java程序中明确导入该包。使用import语句可以完成此功能。
import package1[.package2].(classname|*)
javadoc命令是用来生成自己的API文档的。
参数信息
在命令行中:
javadoc -encoding UTF-8 -charset UTF-8 Doc.java
在IDEA中运行:
Tools->Generate JavaDoc
Java.util.Scanner是Java5的新特征,我们可以通过Scanner类来获取用户的输入。
基本语法:
Scanner s = new Scanner(System.in);
通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。
public class Demo01 {
public static void main(String[] args) {
//创建一个扫描器类型
Scanner s = new Scanner(System.in);
System.out.println("使用next方式接收:");
//判断用户有没有输入字符串
if (s.hasNext()){
//使用next方式接收
String str = s.next(); //程序会等待用户输入完毕
System.out.println("输出的内容为:"+str);
}
//凡是属于IO流的类如果不关闭会一直占用资源,要养成习惯用完就关掉
s.close();
}
}
public class Demo02 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("使用nextLine方式接收:");
if (scanner.hasNextLine()){
String str = scanner.nextLine();
System.out.println("输出的内容为:"+str);
}
scanner.close();
}
}
public class Demo03 {
public static void main(String[] args) {
//我们可以输入多个数字,并求其和与平均数,每输入一个数字用回车确认,通过输入非数字来结束输入并输出执行结果:
Scanner scanner = new Scanner(System.in);
//和
double sum = 0;
//输入多少数字
int m = 0;
//通过循环判断是否还有输入,并在里面对每一次进行求和和统计
while (scanner.hasNextDouble()){
double x = scanner.nextDouble();
m++;
sum = sum + x;
}
System.out.println(m+"个数的和为"+sum);
System.out.println(m+"个数的平均值为"+(sum/m));
scanner.close();
}
}
JAVA的基本结构就是顺序结构,除非特别指明,否则就按照顺序一句一句执行。
顺序结构是最简单的算法结构。
语句与语句之间,框与框之间是按照从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,它是任何一个算法都离不开的一种基本算法结构。
public class Demo04 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String s = scanner.nextLine();
//equals判断字符串是否相等
if (s.equals("Hello")){
System.out.println(s);
}else if (s.equals("World")){
System.out.println("World");
}else{
if(s.equals("666")){
System.out.println("999");
}
System.out.println("Error");
}
System.out.println("End");
scanner.close();
}
}
switch(expression){
case value1 :
//语句
break; //可选 如果不写,会再执行下一个case,case穿透!
case value2 :
//语句
break; //可选
default : //可选
//语句
}
while是最基本的循环,它的结构为:
while (布尔表达式){
//循环内容
}
只要布尔表达式为true,循环就会一致执行下去。
我们大多数情况是会让循环停止下来的,我们需要一个表达式失效的方式来结束循环。
少部分情况需要循环一直执行,比如服务器的请求响应监听等。
循环条件一直为true就会造成无限循环【死循环】,我们正常的业务编程中应该尽量避免死循环。会影响程序性能或者造成程序卡死崩溃!
public class WhileDemo01 {
public static void main(String[] args) {
//计算1+2+3+……+100
int i = 0;
int sum = 0;
while (i<100){
sum = sum + i;
i++;
}
System.out.println(i);
}
}
对于while语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件也至少要执行一次。
do…while循环和while循环相似,不同的是,do…while循环至少会执行一次。
do{
//代码语句
}while(布尔表达式)
while和do…while的区别
虽然所有的循环结构都可以用while或者do…while表示,但Java提供了另一种语句——for循环,使一些循环结构变得更加简单。
for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
for循环执行的次数实在执行前就决定的。语法格式如下:
for(初始化;布尔表达式;更新){
//代码语句
}
//死循环
for(;;){
}
//九九乘法表
public class ForDemo01 {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(i+"*"+j+"="+(i*j)+"\t");
}
System.out.println();
}
}
}
Java5引入了一种主要用于数组或集合的增强型for循环。
Java增强for循环语法格式如下:
for(声明语句:表达式){
//代码语句
}
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者返回值为数组的方法。
public class ForDemo02 {
public static void main(String[] args) {
//定义一个数组
int[] numbers = {10,20,30,40};
for (int x:numbers){
System.out.println(x);
}
}
}
break在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
continue语句在循环语句体中,用于终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判断。
关于goto关键字(了解)
goto关键字很早就在程序设计语言中出现。尽管goto仍是Java的一个保留字,但未在语言中得到正式使用;Java没有goto。然而,在break和continue这两个关键字的身上,我们仍然能看出一些goto的影子–带标签的break和continue。
“标签”是指后面跟一个冒号的标识符,如:label:
对Java来说唯一用到标签的地方是在循环语句之前。而在循环之前设置标签的唯一理由是:我们希望在其中嵌套另一个循环,由于break和continue关键字通常只中断当前循环,但若随同标签使用,它们就会中断到存在标签的地方。
public class LabelDemo {
public static void main(String[] args) {
//打印101-150之间所有的质数
int count = 0;
//标签
outer:
for (int i = 101; i < 150; i++) {
for (int j = 2; j < i/2; j++) {
if (i%j==0){
continue outer;
}
}
System.out.print(i+" ");
}
}
}
//public 修饰符 返回值类型 方法名(参数类型 参数名)
public static int add(int a,int b){
//方法体
//......
return a+b;//返回值
}
调用方法:对象名.方法名(实参列表)
Java支持两种调用方法的方式,根据方法是否返回值来选择。
当方法返回一个值的时候,方法调用通常被当做一个值,例如:
int larger = max(30,40);
如果方法返回值是void,方法调用一定是一条语句。
System.out.println('Hello');
Java都是值传递。
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
方法的重载的规则:
实现理论:
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
有时候你希望运行一个程序的时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
public class CommandLine {
public static void main(String args[]){
for(int i=0;i<args.length;i++){
System.out.println("args["+i+"]:"+args[i]);
}
}
}
在命令行中运行编译然后执行。
javac CommandLine
java CommandLine this is args
public static void printMax(double... numbers){
if(numbers.length == 0){
System.out.println("No argument passed");
return;
}
double result = numbers[0];
//排序
for(int i = 1; i < numbers.length; i++){
if(numbers[i]>result){
result = numbers[i];
}
}
System.out.println(result);
}
printMax(1,2,3,4,5);
printMax(new Double[]{1,2,3,4,5})
//计算阶乘 5!=5*4*3*2*1
public static int f(int n){
if(n==1){
return 1;
}else{
return f(n-1);
}
}
首先必须声明数组变量,才能在程序使用数组。下面是声明数组变量的语法:
dataType[] arrayRefVar; //首选的方法
dataType arrayRefVar[]; //效果相同,但不是首选的方法
Java语言使用new操作符来创建数组,语法如下:
dataType[] arrayRefVar = new dataType[arraySize];
数组的元素是通过索引访问的,数组索引从0开始。
获取数组的长度:
arrays.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;
数组的默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中每个元素也被按照实例变量同样的方式被隐式初始化。
Java内存分析(简单分析)
下标合法区间:[0,length-1],如果越界就会报错
public static void main(String[] args){
int[] a = new int[2];
System.out.println(a[2]);
}
ArrayIndexOutOfBoundsException:数组下标越界异常!
小结:
普通的for循环
int[] arrays = {1,2,3,4,5};
for(int i=0;i<arrays.length;i++){
System.out.println(arrays[i]);
}
for-each的使用
int[] arrays = {1,2,3,4,5};
//JDK1.5 没有下标
for(int array: arrays){
System.out.println(array);
}
数组作方法入参
public static void printArray(int[] arrays){
//方法代码
}
数组作返回值
public static void printArray(int[] arrays){
int[] res = new int[arrays.length];
//反转
for(int i=0,j=res.length-1;i<arrays.length;i++,j--){
res[j]=arrays[i];
}
return res;
}
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一堆数组,其中每一个元素都是一个一维数组。
二维数组
int a[][] = new int[2][5];
int[][] array = {{1,2},{3,4}};
Java的核心思想就是oop(面向对象编程)
public class Student{
//属性
String name; //null
int age; //0
//方法
public void study(){
System.out.println(this.name+"在学习")
}
}
public class Application{
public static void main(String[] args){
//类:抽象的,实例化
//类实例化后会返回一个自己的对象
//student对象就是一个student类的具体实例
Student xiaoming = new Student();
Student xh = new Student();
xiaoming.name="小明";
xiaoming.age=3;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
xh.name="小红";
xh.age=4;
System.out.println(xh.name);
System.out.println(xh.age);
}
}
public class Person{
//即使一个类什么都不写,它也会存在一个方法
String name;
//显式的定义构造器
//实例初始化
//无参构造
public Person(){
this.name = "jy";
}
//有参构造
//一但定义了有参构造,无参构造必须显式定义
//方法的重载
//IDEA alt+insert快速创建构造函数
public Person(String name){
this.name = name;
}
}
类与对象
类是一个模板,抽象的。
对象是一个具体的实例。
方法
定义,调用
对应的引用
引用类型:对象是通过引用来操作的(栈–>堆)
属性
字段Field 成员变量
默认初始化
修饰符 属性类型 属性名 = 属性值
对象的创建和使用
类
静态的属性:属性
动态的行为:方法
该露的露,该藏的藏
我们的程序设计要追求“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合就是尽量暴露少量的方法给外部使用。
封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏。
记住这句话就够了:私有属性,get/set
public class Student{
private String name; //私有属性
//外部不可直接操作
//提供一些可以操作这个属性的方法
//get 获取这个数据
public String getName(){
return this.name;
}
//set 设置这个数据
public void getName(String name){
this.name=name;
}
}
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
extands的意思是“拓展”。子类是父类的拓展。
JAVA中类只有单继承,没有多继承。
继承是类和类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
子类和父类之间,从意义上讲应该具有“is a”的关系。
object类
在java中,所有的类都直接或者间接地继承Object类
super
当前类用this,父类用super
方法重写
都是方法的重写,和属性无关
//Student继承Person
//子类继承了父类,就会拥有父类的所有方法
//私有的东西无法被继承
public class Person /*extents Object*/ {
//构造器
public Person(){
}
}
public class Student extents Person{
//构造器
public Student() {
//可以隐藏,子类构造器自动调用父类无参构造
super();//调用父类的构造器,必须要在子类构造器的第一行
}
}
super注意点:
super调用父类的构造方法,必须在构造方法的第一个
super必须只能出现在子类的方法或者构造函数中
super和this不能同时调用构造方法
//不能同时调用
spuer();
this();
和this的区别
//A类继承B类,两者都有静态方法test
public class B{
public static void test(){
System.out.println("B")
}
}
public class A extents B{
public static void test(){
System.out.println("A")
}
}
//方法的调用只和左边定义的数据类型有关
A a = new A();
a.test(); //A
B b = new A(); //父类的引用指向了子类
b.test(); //B
public class B{
public void test(){
System.out.println("B")
}
}
public class A extents B{
//重写
@Override
public void test(){
System.out.println("A")
}
}
A a = new A();
a.test(); //A
B b = new A();
b.test(); //A
重写:需要有继承关系,子类重写父类的方法
即同一个方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多(父类,有关系的类)。
Student s1 = new Student();
Person s2 = new Student();
Object s3 = new Student();
多态存在的条件
注意多态是方法的多态,属性没有多态。
instanceof(类型转换 引用类型)
instanceof必须要存在父子关系才能通过编译,否则无法使用
//Object > String
//Object > Person > Teacher
//Object > Person > Student
Object obj = new Student;
System.out.println(obj instanceof Student); //true
System.out.println(obj instanceof Person); //true
System.out.println(obj instanceof Object); //true
System.out.println(obj instanceof Teacher); //false
System.out.println(obj instanceof String); //false
Person obj1 = new Student;
System.out.println(obj1 instanceof Student); //true
System.out.println(obj1 instanceof Person); //true
System.out.println(obj1 instanceof Object); //true
System.out.println(obj1 instanceof Teacher); //false
//System.out.println(obj1 instanceof String); //编译报错
Student obj2 = new Student;
System.out.println(obj2 instanceof Student); //true
System.out.println(obj2 instanceof Person); //true
System.out.println(obj2 instanceof Object); //true
//System.out.println(obj2 instanceof Teacher); //编译报错
//System.out.println(obj1 instanceof String); //编译报错
//静态导入包
import static java.lang.Math.PI;
public class Static {
private static int age; //静态的变量 (多线程)
private double score; //非静态的变量
//2执行顺序 赋初始值
{
//匿名代码块
System.out.println("匿名代码块");
}
//1执行顺序 只执行一次
static {
//静态代码块
System.out.println("静态代码块");
}
//3执行顺序
public Static(){
//构造方法
System.out.println("构造方法");
}
public void run(){
System.out.println("run");
}
public static void go(){
System.out.println("go");
}
public static void main(String[] args) {
Static s1 = new Static();
Static s2 = new Static();
System.out.println(Static.age); //0
//System.out.println(Static.score); //Non-static field 'score' cannot be referenced from a static context
System.out.println(s1.age); //0
System.out.println(s1.score); //0.0
//Static.run(); //Non-static method 'run()' cannot be referenced from a static context
Static.go();
s1.run();
s1.go();
}
}
//abstract抽象类 类是单继承 接口可以实现多继承
public abstract class Action {
//添加约束,由创建者实现
//abstract,抽象方法,只有方法名字,没有方法实现
public abstract void doSomething();
//抽象类中可以写普通方法,抽象方法必须在抽象类中
}
//抽象类的所有方法,继承了它的子类都必须要实现它的方法
//如果子类也是abstract抽象类,则由子子类继承实现
public class A extends Action{
@Override //必须方法重写
public void doSomething() {
}
}
普通类:只有具体实现
抽象类:具体实现和规范(抽象方法)都有
接口:只有规范,自己无法写方法,专业的约束。约束和实现分离:面向接口编程
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是……则必须能……”的思想。例如:如果你是汽车,则必须能跑。
接口的本质是契约,就像我们人间的法律一样。制定好后大家都遵守。
OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计模式都只针对具备了抽象能力的语言(比如java、c++、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
声明类的关键字是class,声明接口的关键字是interface
//interface 定义的关键字,接口都需要有实现类
//接口中没有构造方法,不能被实例化
public interface Demo {
//默认定义为常量 public static final
int AGE = 99;
//接口中所有定义的方法其实都是抽象的public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
public interface Demo2 {
void run();
}
// 抽象类 extents
//类 可以实现接口 implements接口
//实现了接口的类 就需要重写接口中的方法
//多继承通过接口实现多继承
public class Demo1 implements Demo,Demo2{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void run() {
}
}
public class Demo03 {
private int id;
public void out(){
System.out.println("这是一个外部类方法");
}
//成员内部类,静态内部类加一个static
class Inner{
public void in(){
System.out.println("这是一个内部类方法");
//局部内部类
class In(){
}
}
//获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
public class Demo01 {
public static void main(String[] args) {
Demo03 demo03 = new Demo03();
//通过这个外部类来实例化内部类
Demo03.Inner inner = demo03.new Inner();
inner.getID();
//匿名内部类
//没有名字初始化类,不用将实例保存到变量中
demo03.new Inner().getID();
}
}
内部类的场景还有很多,遇到再进行理解!
Error和Exception的区别:Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时Java虚拟机(JVM)一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
抛出异常
捕获异常
异常处理的五个关键字
try、catch、finally、throw、throws
public class Demo04 {
public static void main(String[] args) {
int a=1;
int b=0;
//如果需要捕获多个异常 需要从小到大捕获异常类型
try { //try监控区域
System.out.println(a/b);
}catch (ArithmeticException e){ //捕获异常 catch里面的参数就是想要捕获异常的类型 可以写多个catch
System.out.println("error");
}finally { //处理善后 不管是否出错都会最后执行
System.out.println("finally");
}
// finally可以不要
}
//假设方法处理不了这个异常,方法上主动抛出异常
public void test(int a,int b) throws ArithmeticException{
if (b==0){
throw new ArithmeticException(); //主动抛出异常 一般在方法中使用
}
}
}
//自定义的异常类
public class Demo05 extends Exception{
private int detail;
public Demo05(int a){
this.detail = a;
}
//toString 打印错误信息
@Override
public String toString() {
return "Demo05{" +
"detail=" + detail +
'}';
}
}