IdeFun

努力不一定成功,但不努力真的很舒服。

0%

Java学习笔记

Java学习笔记

命令行运行

javac -encoding utf8 demo.java
java demo

Java基础

注释

单行注释

单行注释使用//

public class HelloWorld {
public static void main(String[] args) {
// 输出hello world
System.out.println("hello world");
}
}

多行注释

多行注释使用/**/

public class HelloWorld {
public static void main(String[] args) {
/* 输出hello
world*/
System.out.println("hello world");
}
}

文档注释

Javadoc:文档注释

/**
* @Description HelloWorld
* @Author idefun
*/

标识符和关键字

关键字

Java关键字类别 Java关键字 关键字含义
访问控制 private 一种访问控制方式:私用模式,访问控制修饰符,可以应用于类、方法或字段(在类中声明的变量)
访问控制 protected 一种访问控制方式:保护模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符
访问控制 public 一种访问控制方式:共用模式,可以应用于类、方法或字段(在类中声明的变量)的访问控制修饰符。
类、方法和变量修饰符 abstract 表明类或者成员方法具有抽象属性,用于修改类或方法
类、方法和变量修饰符 class 声明一个类,用来声明新的Java类
类、方法和变量修饰符 extends 表明一个类型是另一个类型的子类型。对于类,可以是另一个类或者抽象类;对于接口,可以是另一个接口
类、方法和变量修饰符 final 用来说明最终属性,表明一个类不能派生出子类,或者成员方法不能被覆盖,或者成员域的值不能被改变,用来定义常量
类、方法和变量修饰符 implements 表明一个类实现了给定的接口
类、方法和变量修饰符 interface 接口
类、方法和变量修饰符 native 用来声明一个方法是由与计算机相关的语言(如C/C++/FORTRAN语言)实现的
类、方法和变量修饰符 new 用来创建新实例对象
类、方法和变量修饰符 static 表明具有静态属性
类、方法和变量修饰符 strictfp 用来声明FP_strict(单精度或双精度浮点数)表达式遵循IEEE 754算术规范
类、方法和变量修饰符 synchronized 表明一段代码需要同步执行
类、方法和变量修饰符 transient 声明不用序列化的成员域
类、方法和变量修饰符 volatile 表明两个或者多个变量必须同步地发生变化
程序控制 break 提前跳出一个块
程序控制 continue 回到一个块的开始处
程序控制 return 从成员方法中返回数据
程序控制 do 用在do-while循环结构中
程序控制 while 用在循环结构中
程序控制 if 条件语句的引导词
程序控制 else 用在条件语句中,表明当条件不成立时的分支
程序控制 for 一种循环结构的引导词
程序控制 instanceof 用来测试一个对象是否是指定类型的实例对象
程序控制 switch 分支语句结构的引导词
程序控制 case 用在switch语句之中,表示其中的一个分支
程序控制 default 默认,例如:用在switch语句中,表明一个默认的分支。Java8 中也作用于声明接口函数的默认实现
错误处理 try 尝试一个可能抛出异常的程序块
错误处理 catch 用在异常处理中,用来捕捉异常
错误处理 throw 抛出一个异常
错误处理 throws 声明在当前定义的成员方法中所有需要抛出的异常
包相关 import 表明要访问指定的类或包
包相关 package
基本类型 boolean 基本数据类型之一,声明布尔类型的关键字
基本类型 byte 基本数据类型之一,字节类型
基本类型 char 基本数据类型之一,字符类型
基本类型 double 基本数据类型之一,双精度浮点数类型
基本类型 float 基本数据类型之一,单精度浮点数类型
基本类型 int 基本数据类型之一,整数类型
基本类型 long 基本数据类型之一,长整数类型
基本类型 short 基本数据类型之一,短整数类型
基本类型 null 空,表示无值,不能将null赋给原始类型(byte、short、int、long、char、float、double、boolean)变量
基本类型 true 真,boolean变量的两个合法值中的一个
基本类型 false 假,boolean变量的两个合法值之一
变量引用 super 表明当前对象的父类型的引用或者父类型的构造方法
变量引用 this 指向当前实例对象的引用,用于引用当前实例
变量引用 void 声明当前成员方法没有返回值,void可以用作方法的返回类型,以指示该方法不返回值
保留字 goto 保留关键字,没有具体含义
保留字 const 保留关键字,没有具体含义,是一个类型修饰符,使用const声明的对象不能更新
  • 所有标识符应该以字母A-Za-z、美元符$、或下划线_开始
  • 首字母之后可以是字母、美元符、下划线或数字的组合
  • 标识符是大小写敏感的
  • 可以使用中文命名,但不建议
  • 不能使用关键字作为变量名或方法名

数据类型

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

弱类型语言:类型可以被忽略,一个变量被定义类型,该变量可以根据环境变化自动进行转换,不需要经过显性强制转换

java的数据类型分为两大类:

  • 基本类型
  • 引用类型

image-20211229173211924

注意:long型赋值时要加上L(大写),float型要加上f或F

public class Demo02 {
public static void main(String[] args) {
//八大基本数据类型
//整数
byte n1=10;
int n2=20;
short n3=30;
long n4= 30L;
//浮点数
float n5=40.2F;
double n6=12.44;
//字符
char n7='好';
String n8="你好";
//布尔值
boolean n9=true;
System.out.println(n9);
}
}

注意:八进制要在前面加0,十六进制要加0x,二进制加0b;

尽量不要使用浮点数进行比较,使用BigDecimal类

public class Demo03 {
public static void main(String[] args){
//整数拓展 进制
int i=10;
int i1=010; //八进制
int i2=0x10; //十六进制
int i3=0b10;
System.out.println(i);
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);
//浮点数拓展
float i4=0.1F;
double i5=1.0/10;
System.out.println(i4==i5);//false
float i6=123344443342342245f;
float i7=i6+1;
//明显i6!=i7,但float表示的字长有限,i6超出范围,所以会输出true
//尽量不使用浮点数比较,使用BigDecimal类
System.out.println(i6==i7);//true
//字符拓展
char a1='a';
char a2='中';
System.out.println(a1);
System.out.println((int)a1);//强制转换
System.out.println(a2);
System.out.println((int)a2);//强制转换
//所有字符本质还是数字
//编码 Unicode 2字节 0-65536
//U0000 UFFFF
char a3='\u0061';
System.out.println(a3);
//转义字符
System.out.println("hello\tworld");

String sa=new String("hello world");
String sb=new String("hello world");
System.out.println(sa==sb);//比较地址
String sc="hello world";
String sd="hello world";
System.out.println(sc==sd);//比较内存

//布尔值拓展
boolean flag=true;
if(flag){
System.out.println("你好");
}
}
}

类型转换

由于java是强类型语言,所以进行有些计算时需要类型转换。

类型转换分为:

  • 强制类型转换

  • 自动类型转换

public class Demo04 {
public static void main(String[] args) {
int i=128;
byte b=(byte)i;//内存溢出
//byte最大127
//强制转换 (类型)变量名 高-->低
System.out.println(i);//128
System.out.println(b);//-128
//自动转换 低-->高
//byte,short,char-->int-->long-->float-->double
double d=i;
System.out.println(d);
System.out.println((int)23.6);
System.out.println((int)45.88f);
char c='a';
int i1=c+1;
System.out.println(i1);
/*
注意:
1.不能对布尔值进行转换
2.不能把对象类型转换为不相干类型
3.在高容量转换到低容量时,强制转换;反之自动转换
4.转换的时候可能存在内存溢出,或精度问题
*/
}
}
public class Demo05 {
public static void main(String[] args) {
int money=10_0000_0000;
//数字之间可以使用下划线分割
int years=20;
int total1=money*years;
// money和years为int,乘积也为int,再由int转为long
long total2=money*years;
long total3=money*((long)years);
System.out.println(total1);
System.out.println(total2);
System.out.println(total3);
}
}

变量

public class Demo06 {
//类变量
static int test=10;
//实例变量:从属于对象,如果不初始化,会自动初始化为这个类型的默认值
String name;
int age;

//main方法
public static void main(String[] args) {
//局部变量 必须声明和初始化值
int a=1;
int b=2;
int c=3;
String name="hello world";
char x='X';
double pi=3.14;
System.out.println(a);
Demo06 demo06 =new Demo06();
System.out.println(demo06.age);
System.out.println(demo06.name);
System.out.println(test);
}
//其他方法
public void add(){
// System.out.println(a);
}
}

基本运算符

package operator;

public class Demo05 {
//逻辑运算符
public static void main(String[] args) {
boolean a=true;
boolean b=false;
System.out.println("a&&b:"+(a&&b));
System.out.println("a||b:"+(a||b));
System.out.println("!(a&&b)"+!(a&&b));
//短路运算 &&
int c=5;
boolean d=(c<4)&&(c++<4);
//c<4为false,后面的就不用执行
System.out.println(c);//5
System.out.println(d);//false
//短路运算 ||
int e=6;
boolean f=(e>4)||(e++>4);
System.out.println(e);
System.out.println(f);
//位运算 效率高
// << 表示乘2, >>表示除2
System.out.println(2<<3);
}
}
package operator;

public class Demo07 {
public static void main(String[] args) {
int a=10;
int b=20;
a+=b;
System.out.println(a);
//+可做字符串连接符,一方出现string类型,结果自动转成string
System.out.println(""+a+b);
System.out.println((""+(a+b)).getClass().toString());
}
}

package operator;

public class Demo08 {
public static void main(String[] args) {
//三元运算符
int score=80;
String type=score<60?"不及格":"及格";
System.out.println(type);
}
}

包机制

为了更好地组织类, Java 提供了包机制,用于区别类名的命名空间。
包语句的语法格式为:
package pkg1[. pkg2[. pkg..]];
一般利用公司域名倒置作为包名: www.baidu.com com.baidu.www
为了能够使用某一个包的成员,我们需要在Java程序中明确导入该包。使用”import”语句可完成此功能:
import package1[.package..].(classname|*);

注意:import一定要在package下面

Javadoc

javadoc命令是用来生成自己API文档的

使用命令行生成

javadoc 文件名.java

使用idea生成

image-20220121110404280

Java流程控制

用户交互scanner

java.util.scanner是Java5的新特征,我们可以通过scanner类获取用户的输入。

基本语法:

Scanner s=new Scanner(System.in);

通过Scanner类的next()和nextLine()方法获取输入的字符串,在读取前一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。

next()和hasNext()配套使用;nextLine()hasNextLine()配套使用。

  • hasNext()方法会判断接下来是否有非空字符.如果有,则返回true,否则返回false
  • hasNextLine() 方法会根据行匹配模式去判断接下来是否有一行(包括空行),如果有,则返回true,否则返回false

next():

  1. 一定要读取到有效字符后才可以结束输入。
  2. 对输入有效字符之前遇到的空白,next() 方法会自动将其去掉。
  3. 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
  4. next() 不能得到带有空格的字符串。

nextLine():

  1. 以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符。
  2. 可以获得空白。
package com.idefun.scanner;

import java.util.Scanner;

public class Demo01 {
public static void main(String[] args) {
//创建扫描器对象,用于接收键盘数据
Scanner scanner = new Scanner(System.in);
System.out.println("使用next方式接收:");
//判断用户是否输入字符串
if(scanner.hasNext()){
String str=scanner.next();
//如果输入有空格,则next只能接收空格之前的内容,如:hello world,接收hello
System.out.println("输出:"+str);
}
//凡是属于IO流的类如果不关闭会一直占用资源
scanner.close();
}
}
package com.idefun.scanner;

import java.util.Scanner;

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();
}
}

选择结构

if选择结构

package com.idefun.struct;

import java.util.Scanner;
//if 选择结构
public class Demo03 {
public static void main(String[] args) {
Scanner scanner =new Scanner(System.in);
System.out.println("请输入成绩:");
float score=0.0f;
score=scanner.nextFloat();
if(score>=60 && score<=100){
System.out.println("及格");
}
else if(score<60 && score>=0){
System.out.println("不及格");
}
else{
System.out.println("错误");
}
scanner.close();
}
}

switch选择结构

package com.idefun.struct;
//switch多选择结构
public class Demo04 {
public static void main(String[] args) {
char grade='C';
switch (grade){
case 'A':
System.out.println("优秀");
//如果没有break将输出所有
break;
case 'B':
System.out.println("良好");
break;
case 'C':
System.out.println("及格");
break;
case 'D':
System.out.println("再接再厉");
break;
default:
System.out.println("查询无果");
}
}
}
package com.idefun.struct;

public class Demo05 {
public static void main(String[] args) {
//jdk7及之后支持字符串
String name="test";
switch (name){
case "htl":
System.out.println("htl");
break;
case "gee":
System.out.println("gee");
break;
default:
System.out.println("test");
}
}
}

循环结构

while循环

package com.idefun.struct;

public class Demo06 {
public static void main(String[] args) {
//计算1+2+3+...+100
int i=0;
int sum=0;
while(i<100){
i++;
sum+=i;
}
System.out.println(sum);
}
}

do while循环

package com.idefun.struct;

public class Demo07 {
public static void main(String[] args) {
//while先判断后执行,dowhile先执行后判断,dowhile保证循环体被至少执行一次
int i=0;
int sum=0;
do {
i++;
sum+=i;
}while (i<100);
System.out.println(sum);
}
}

for循环

小技巧:在idea中输入100.for并回车即可生成0-100for循环

死循环: for(;;){}

package com.idefun.struct;

public class Demo08 {
public static void main(String[] args) {
int sum=0;
for (int i = 0; i <= 100; i++) {
sum+=i;
}
System.out.println(sum);
}
}
package com.idefun.struct;

public class Demo09 {
public static void main(String[] args) {
//输出1-1000之间能被5整除的数,且每行三个
//println输出完会换行,print输出完不会换行
for (int i = 1; i <= 1000; i++) {
if(i%5==0){
System.out.print(i+"\t");
}
if(i%15==0){
System.out.println();
}
}
}
}
package com.idefun.struct;
//打印九九乘法表
public class Demo10 {
public static void main(String[] args) {
for(int i=1;i<10;i++){
for(int j=1;j<=i;j++){
System.out.print(j+"*"+i+"="+(i*j)+"\t");
//注意必须是双引号,否则字符会与变量进行运算
if(j==i){
System.out.println();
}

}
}
}
}

增强for循环

package com.idefun.struct;

public class Demo11 {
public static void main(String[] args) {
int[] nums={10,20,30,40,50};
//遍历数组元素
for(int x:nums){
System.out.println(x);
}
}
}

终止循环

打印101-105之间的质数(注意比较下面两个代码)

package com.idefun.struct;

public class Demo12 {
public static void main(String[] args) {
//打印101-105之间的质数
int n=0;
for(int i=101;i<150;i++){
int flag=0;
for(int j=2;j<=i/2;j++){
if(i%j==0){
flag=1;
break;
}
}
if(flag==0){
System.out.print(i+"\t");
}
}
}
}
package com.idefun.struct;

public class Demo13 {
public static void main(String[] args) {
//打印101-105之间的质数
int n=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+"\t");
}
}
}

Java方法

package com.idefun.method;

public class Demo01 {
//main方法
public static void main(String[] args) {
int sum=add(1,3);
System.out.println(sum);
}
//不加static无法在main方法中访问
//一个方法只做一个功能
public static int add(int a, int b){
return a+b;
}
}

static的作用是,将属性或者方法修饰为该类的共享成员,即这个属性或方法是该类实例化的所有对象之间共享的,不为某个实例对象所有,static属性或方法是存储在内存的公共区,一个类中,一个static变量只会有一个内存空间,虽然有多个类实例,但这些类实例中的这个static变量会共享同一个内存空间。

方法重载

package com.idefun.method;

public class Demo03 {
public static void main(String[] args) {
double a=10.0;
int b=5;
System.out.println(max(a,b));
}
public static int max(int a,int b){
return a>b?a:b;
}
public static double max(double a,double b){
return a>b?a:b;
}
}

可变参数

在方法声明中,在指定参数类型后加一个省略号(…)。

一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。

package com.idefun.method;
//可变参数(不定项)


public class Demo05 {
public static void main(String[] args)
{
Demo05 demo05=new Demo05();
demo05.test(1,3,45);
demo05.test(new int[]{2,4,7});
}
public void test(int... i){
for (int k : i) {
System.out.println(k);
}
}
}

递归

递归结构包括两个部分:

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

递归要找好终止条件.

package com.idefun.method;

public class Demo06 {
public static void main(String[] args) {
Demo06 demo06=new Demo06();

System.out.println(demo06.factorial(3));
}
public int factorial(int n){
// if(n>1){
// n*=factorial(n-1);
// return n;
// }
// else {
// return 1;
// }
if(n==1){
return 1;
}
else{
n*=factorial(n-1);
return n;
}
}
}

Java数组

数组声明创建

声明数组的语法:

dataType[] array; //首选方法
dataTyep array[];

创建数组语法:

dataType array=new dataType(arraySize);

三种初始化

image-20220122102129791

image-20220122103935274

静态初始化

int[] a={1,2,3};
Man[] mans={new Man(1,1),new Man(2,1)};

动态初始化

int[] a=new int[2];
a[0]=1;
a[1]=2;

默认初始化

数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也按照实例变量同样的方式被隐式初始化。

package com.idefun.array;

public class Demo01 {
public static void main(String[] args) {
//静态初始化
int [] a={1,2,3,4};
System.out.println(a[2]);
// 动态初始化
int[] b=new int[10];
b[0]=10;
System.out.println(b[0]);
System.out.println(b[4]);
//b[4],b[8]未进行动态初始化,被默认初始化为0
System.out.println(b[8]);
}
}

数组的四个基本特点

  • 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
  • 其元素必须是相同类型,不允许出现混合类型。
  • 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
  • 数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量.

数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。

ArrayIndexOutOfBoundsException:数组下标越界异常!

二维数组

int a[][]=new int[3][2];
package com.idefun.array;

public class Demo02 {
public static void main(String[] args) {
//[3,2]
int[][] array={{1,2},{3,4},{5,6}};
System.out.println(array.length);
System.out.println(array[0].length);
// for(int i=0;i<3;i++){
// for(int j=0;j<2;j++){
// System.out.println(array[i][j]);
// }
// }
for(int i=0;i<array.length;i++){
for(int j=0;j<array[i].length;j++){
System.out.println(array[i][j]);
}
}

}
}

Arrays类

  • 数组的工具类java.util.Arrays
  • 由于数组对象本身并没有什么方法可以供我们调用,但API中提供了一个工具类Arrays供我们使用,从而可以对数据对象进行一些基本的操作。
  • Arrays类中的方法都是static修饰的静态方法,在使用的时候可以直接使用类名进行调用,而”不用”使用对象来调用(注意:是”不用”而不是”不能”)

具有以下常用功能:

  • 给数组赋值:通过fill方法。
  • 对数组排序:通过sort方法,按升序。
  • 比较数组:通过equals方法比较数组中元素值是否相等。
  • 查找数组元素:通过binarySearch方法能对排序好的数组进行二分查找法操作。

稀疏数组

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

稀疏数组的处理方式是:

  • 记录数组一共有几行几列,有多少个不同值
  • 把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模

image-20220122143536121

package com.idefun.array;
//稀疏数组
public class Demo05 {
public static void main(String[] args) {
//1.创建一个二维数组 11*11 0:没有棋子 1:黑棋 2:白棋
int[][] array1=new int[11][11];
array1[1][2]=1;
array1[2][3]=2;
System.out.println("原始数组:");
for(int[] ints:array1){
for(int j:ints){
System.out.print(j+"\t");
}
System.out.println();
}

//转为稀疏数组
//获取有效值个数
int sum=0;
for (int i = 0; i < 11; i++) {
for (int i1 = 0; i1 < 11; i1++) {
if(array1[i][i1]!=0){
sum++;
}
}
}
System.out.println("有效值个数:"+sum);
//2.创建一个稀疏数组
int[][] array2=new int[sum+1][3];
array2[0][0]=11;
array2[0][1]=11;
array2[0][2]=sum;
int n=1;
for (int i = 0; i < 11; i++) {
for (int i1 = 0; i1 < 11; i1++) {
if(array1[i][i1]!=0){
array2[n][0]=i;
array2[n][1]=i1;
array2[n][2]=array1[i][i1];
n++;
}
}
}
System.out.println("稀疏数组");
for (int[] ints : array2) {
for (int anInt : ints) {
System.out.print(anInt+"\t");
}
System.out.println();
}
System.out.println("还原");
int[][] array3=new int[array2[0][0]][array2[0][1]];
for (int i = 1; i <=array2[0][2] ; i++) {
array3[array2[i][0]][array2[i][1]]=array2[i][2];
}
for(int[] ints:array3){
for(int j:ints){
System.out.print(j+"\t");
}
System.out.println();
}
}
}

面向对象编程

在同一个类中

  • 对于静态方法,其他的静态或非静态方法都可以直接调用它。
  • 对于非静态方法,其他的非静态方法是可以直接调用它的,但是其他静态方法只有通过对象才能调用它。静态方法不能被非静态方法覆盖。

在不同类中

  • 静态方法,则通过类名与对象都可以调用(但通过对象的方式不建议使用,因为它属于非静态调用的方式)
  • 非静态方法,则只能通过对象才可以调用它
package com.idefun.oop;

public class Demo03 {
public static void main(String[] args) {
Demo03 demo03=new Demo03();
demo03.a();
}
public void a(){
System.out.println("a");
//a和b均不是静态方法时,a和b可以直接相互调用
b();
}
public void b(){
System.out.println("b");
}
public static void c(){
System.out.println("c");
}
}
package com.idefun.oop;

public class Demo04 {
public static void main(String[] args) {
Demo03.c();
Demo03 demo03=new Demo03();
demo03.a();
demo03.c();
}
}

值传递和引用传递

package com.idefun.oop;
//值传递
public class Demo05 {
public static void main(String[] args) {
int a=1;
System.out.println(a);
change(a);
System.out.println(a);
}
public static void change(int a){
a=10;
}
}
package com.idefun.oop;
//引用传递:对象,本质还是值传递
public class Demo06 {
public static void main(String[] args) {
Person person=new Person();
System.out.println(person.name);
change(person);
System.out.println(person.name);
}
public static void change(Person person){
person.name="hello";
}
}
class Person{
String name;
}

创建和初始化对象

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

类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:

  1. 必须和类的名字相同
  2. 必须没有返回类型,也不能写void

一旦定义有参构造,就要显示定义无参构造

封装

使用快捷键Alt+Insert可快速生成get和set方法

package com.idefun.oop.demo04;

public class Student {
//属性私有
private String name;
private int id;
private int age;
private char sex;
//提供可操作私有属性的方法
//get 获得属性
public String getName(){
return this.name;
}
//set 设置属性值
public void setName(String name){
this.name=name;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public char getSex() {
return sex;
}

public void setSex(char sex) {
this.sex = sex;
}

public int getAge() {
return age;
}

public void setAge(int age) {
if(0<=age && age<=120){
this.age = age;
}else{
System.out.println("error");
}
}
}
package com.idefun.oop;


import com.idefun.oop.demo04.Student;

//一个项目中应该只有一个main方法
public class Applicatipn {
public static void main(String[] args) {
Student s1=new Student();
s1.setName("tom");
System.out.println(s1.getName());
s1.setAge(999);
System.out.println(s1.getAge());
}
}

继承

java中只有单继承没有多继承,接口可以多继承

继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。

子类无法继承父类私有属性。

在java中,所有的类都默认直接或间接继承Object类

super

super()和this()都必须放在构造函数第一行,所有不能同时出现。

package com.idefun.oop.demo05;

public class Person {
protected String name="test1";
public Person(){
System.out.println("Person无参执行了");
}
public void print(){
System.out.println("Person");
}
}
package com.idefun.oop.demo05;

public class Student extends Person{
private String name="test2";
public Student(){
//隐藏代码super()
// super(); //调用父类构造器,且必须要在第一行
//如果父类声明了有参构造,没有声明无参构造,可通过super()直接调用有参构造
System.out.println("Student无参执行了");
}
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
public void print(){
System.out.println("Student");
}
public void test1(String name){
print();
this.print();
super.print();
}
}
package com.idefun.oop;


import com.idefun.oop.demo05.Student;

//一个项目中应该只有一个main方法
public class Applicatipn {
public static void main(String[] args) {
Student student=new Student();
// student.test1("jack");
}
}

方法重写

重写:需要有继承关系,子类重写父类的方法!

  1. 方法名必须相同
  2. 参数列表列表必须相同
  3. 修饰符:范围可以扩大但不能缩小:public >protected>default>private
  4. 抛出的异常:范围,可以被缩小,但不能扩大: ClassNotFoundException —> Exception(大)

多态

多态存在的条件:

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

多态是方法的多态,属性没有多态

package com.idefun.oop.demo07;

public class Person {
public void run(){
System.out.println("Person->run");
}
}
package com.idefun.oop.demo07;

public class Student extends Person{
@Override
public void run() {
System.out.println("Student->run");
}
public void eat(){
System.out.println("Student->eat");
}
}
package com.idefun.oop.demo07;

public class Application {
public static void main(String[] args) {
Student s1=new Student();
Person s2=new Student();
Object s3=new Student();
s2.run();//子类重写父类方法,执行子类方法
s1.run();
// s2.eat();//对象能执行那些方法取决于对象左边的类型
}
}

instanceof和类型转换

instanceof
package com.idefun.oop.demo07;

public class Person {
public void run(){
System.out.println("Person->run");
}
}
package com.idefun.oop.demo07;

public class Student extends Person{

}
package com.idefun.oop.demo07;

public class Teacher extends Person{
}
package com.idefun.oop.demo07;

public class Application {
public static void main(String[] args) {
//Object > String
//Object > Person > Teacher
//Object > Person > Student
Object object = new Student();
System.out.println(object instanceof Student);
System.out.println(object instanceof Person);
System.out.println(object instanceof Teacher);
System.out.println(object instanceof Object);
System.out.println(object instanceof String);
System.out.println("==================");
Person person = new Student();
System.out.println(person instanceof Student);
System.out.println(person instanceof Person);
System.out.println(person instanceof Object);
System.out.println(person instanceof Teacher);
// System.out.println(person instanceof String);
Student student = new Student();
System.out.println("==================");
System.out.println(student instanceof Student);
System.out.println(student instanceof Person);
// System.out.println(student instanceof Teacher);
System.out.println(student instanceof Object);
// System.out.println(student instanceof String);
}
}
类型转换
package com.idefun.oop.demo08;

public class Person {
public void run(){
System.out.println("Person->run");
}
}
package com.idefun.oop.demo08;

public class Student extends Person {
public void go(){
System.out.println("Student->go");
}
}
package com.idefun.oop.demo08;


public class Application {
public static void main(String[] args) {
//类型转换
Person student = new Student();
((Student) student).go();
}
}

static详解

通过final修饰的类无法被继承

package com.idefun.oop.demo09;

public class Student {
private static int age;
private double score;
public void run(){
System.out.println("run");
}
public static void go(){
System.out.println("go");
}
public static void main(String[] args) {
Student student = new Student();
System.out.println(Student.age);
System.out.println(student.age);
System.out.println(student.score);
Student.go();
student.go();
student.run();
}
}
package com.idefun.oop.demo09;

public class Person {
//执行顺序:2
{
//匿名代码块
System.out.println("匿名代码块");
}
//执行顺序:1
static{
//静态代码块,只执行一次
System.out.println("静态代码块");
}
//执行顺序:3
public Person(){
System.out.println("构造方法");
}

public static void main(String[] args) {
Person person1 = new Person();
System.out.println("==============");
Person person2 = new Person();
}
}
package com.idefun.oop.demo09;
//静态导入包
import static java.lang.Math.random;

public class Test {
public static void main(String[] args) {
// System.out.println(Math.random());
System.out.println(random());
}
}

抽象类

抽象类的特征:

  1. 不可被实例化
  2. 抽象类是有构造器的(所有类都有构造器)
  3. 抽象方法所在的类,一定是抽象类(因为抽象方法是没有方法体的,如果所在的类不是抽象类,那么该类可以实例化对象,调用抽象方法,然后无方法体去具体实现功能,则矛盾)
  4. 抽象类可以没有抽象方法的

抽象方法的特征:

  1. 格式,没有方法体,包括{ },例如 public abstract void dink();
  2. 抽象方法只保留方法的功能,具体的执行,交给继承抽象类的子类,由子类重写改抽象方法
  3. 如果子类继承抽象类,并重写了父类的所有的抽象方法,则此子类不是抽象类,可以实例化的
  4. 如果子类继承抽象类,没有重写父类中所有的抽象方法,意味着子类中还有抽象方法,那么此子类必须必须声明为抽象的。
package com.idefun.oop.demo10;
//抽象类
public abstract class Action {
//抽象方法
public abstract void doSomething();
public void run(){
System.out.println("run");
}
}
package com.idefun.oop.demo10;
//抽象类的所有抽象方法,继承了它的子类都必须重写
public class Test extends Action{
@Override
public void doSomething() {

}
}

接口

接口可以看成是一种特殊的类,只能用 interface 关键字修饰。

Java 中的接口具有以下几个特点:

  1. 接口中可以包含变量和方法,变量被隐式指定为 public static final,方法被隐式指定为 public abstract(JDK 1.8 之前)。
  2. 接口支持多继承,即一个接口可以继承(extends)多个接口,间接解决了 Java 中类不能多继承的问题。
  3. 一个类可以同时实现多个接口,一个类实现某个接口则必须实现该接口中的抽象方法,否则该类必须被定义为抽象类。
package com.idefun.oop.demo11;

public interface Test {
//接口中定义属性都是常量 public static final
int AGE=49;
//接口中所有定义都是抽象的 public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
}
package com.idefun.oop.demo11;

public interface Test2 {
void timer();
}
package com.idefun.oop.demo11;
//类可以实现接口
//实现接口的类必须重写接口中所有的方法
public class TestImpl implements Test,Test2{
@Override
public void add(String name) {
System.out.println("add");
}

@Override
public void delete(String name) {
System.out.println();
}

@Override
public void update(String name) {

}

@Override
public void query(String name) {

}

@Override
public void timer() {

}
}

内部类

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类
package com.idefun.oop.demo12;

public class Outer {
private int id=10;
public void out(){
System.out.println("outer");
}
class Inner{
//内部类可直接访问外部类方法和属性
public void in(){
System.out.println("inner");
}
public void getId(){
System.out.println(id);

}
}
}
package com.idefun.oop.demo12;

public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner=outer.new Inner();
outer.out();
inner.in();
inner.getId();
}
}

静态内部类不能访问外部属性和方法

package com.idefun.oop.demo12;

public class Outer {
private int id=10;
public void out(){
System.out.println("outer");
}
public void method(){
//局部内部类
class B{

}
}
// 静态内部类
public static class Inner{
//内部类可直接访问外部类方法和属性
public void in(){
System.out.println("inner");
}

// public void getId(){
// System.out.println(id);
//
// }
}
}
//一个java文件只能有一个public class,可以有多个class

class A{

}
package com.idefun.oop.demo12;

public class Test {
public static void main(String[] args) {
//匿名内部类
//没有名字初始化类,
new Apple().eat();
new UserService(){
@Override
public void hello() {
System.out.println("hello");
}
};
}
}

class Apple{
public void eat(){
System.out.println("apple");
}
}
interface UserService{
void hello();
}

异常

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常:运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误:错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

Java把异常当作对象来处理,并定义一个基类java.lang.Throwable作为所有异常的超类。
在Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常Exception。

Java异常的体系结构

Error

  • Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
  • Java虚拟机运行错误(Virtual MachineError),当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
  • 还有发生在虚拟机试图执行应用时,如类定义错误(NoClassDefFoundError)、链接错误(LinkageError)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。

Exception

  • 在Exception分支中有一个重要的子类RuntimeException (运行时异常)

    • ArrayIndexOutOfBoundsException (数组下标越界)

    • NullPointerException (空指针异常)

    • ArithmeticException (算术异常)

    • MissingResourceException (丢失资源)

    • ClassNotFoundException (找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。

  • 这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生
  • Error和Exception的区别: Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机(JVM)一般会选择终止线程; Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。

异常处理机制

  • 抛出异常
  • 捕获异常
  • 异常处理五个关键字
    • try、catch、finally、throw、throws

idea可使用Ctrl+Alt+T选择语句包裹

package com.idefun.exception;

public class Demo01 {
public static void main(String[] args) {
int a=1;
int b=0;

try{//try监控区域
System.out.println(a/b);
// new Demo01().a();
} catch (Error e){
System.out.println("Error");
} catch (Exception e){
System.out.println("Exception");
} catch (Throwable e){//捕获异常
System.out.println("Throwable");
} finally {//处理善后工作
System.out.println("finally");
}
//try catch必须有,finally可以不要
//可以catch多个异常,最大的异常放在后面
}
public void a(){b();}
public void b(){a();}
}
package com.idefun.exception;

public class Demo02 {
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 (Exception e) {
e.printStackTrace();
} finally {
System.out.println("finally");
}
}
}
package com.idefun.exception;

public class Demo03 {
public static void main(String[] args) {
try {
new Demo03().test(1,0);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
//假设这个方法处理不了异常,则在方法上抛出异常
public void test(int a,int b) throws ArithmeticException{
if(b==0){
//主动抛出异常,一般在方法里
throw new ArithmeticException();
}
System.out.println(a/b);
}
}

自定义异常

  • 使用Java内置的异常类可以描述在编程时出现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承Exception类即可。
  • 在程序中使用自定义异常类,大体可分为以下几个步骤:
    1. 创建自定义异常类。
    2. 在方法中通过throw关键字抛出异常对象。
    3. 如果在当前抛出异常的方法中处理异常,可以使用try-catch语句捕获并处理;否则在方法的声明处通过throws关键字指明要抛出给方法调用者的异常,继续进行下一步操作。
    4. 在出现异常方法的调用者中捕获并处理异常。

多线程

线程创建

image-20220125103856926

Thread

  1. 自定义线程类继承Thread类
  2. 重写run()方法,编写线程执行体
  3. 创建线程对象,调用start()方法启动线程(线程开启不一定立即执行,由CPU调度)
package com.idefun.multithreading;

import org.apache.commons.io.FileUtils;

import java.io.File;
import java.io.IOException;
import java.net.URL;

public class Demo02 extends Thread{
private String url;
private String name;

public Demo02(String url,String name){
this.url=url;
this.name=name;
}
@Override
public void run() {
WebDownloader webDownloader=new WebDownloader();
System.out.println("正在下载"+name);
webDownloader.downloader(this.url,this.name);

}

public static void main(String[] args) {
Demo02 t1 = new Demo02("http://pic.bizhi360.com/bpic/7/10607.jpg","1.jpg");
Demo02 t2 = new Demo02("http://pic.bizhi360.com/litimg/10589.jpg","2.jpg");
Demo02 t3 = new Demo02("http://pic.bizhi360.com/litimg/10572.jpg","3.jpg");

t1.start();
t2.start();
t3.start();
}
}
class WebDownloader{
public void downloader(String url,String name){
try {
FileUtils.copyURLToFile(new URL(url),new File(name));
} catch (IOException e) {
e.printStackTrace();
System.out.println("downloader异常");
}
}
}

runnable

-------------本文结束感谢您的阅读-------------