综述:
Java学习图谱:
常见dos命令:
操作案例:
Java语言的特点:
面向对象
两个基本概念:类、对象
三个基本特性:封装、继承、多态
健壮性、可继承性
write once,run anywhere !
java两种核心机制:Java虚拟机、垃圾回收机制
jdk安装及环境变量配置:
配置参考:
https://www.runoob.com/java/java-environment-setup.html
其他:
在一个Java源文件中可以声明多个class,但是只能有一个类声明为public,而且要求声明为public的类名必须与文件名同名
编译的过程:编译的过程中会生成字节码文件,编译的文件中有多少个类就有多少个字节码文件
标识符:
凡是可以自己命名的地方都叫标识符。
Java语言严格区分大小写
变量:
整数类型:
声明long型变量必须以大写L或者小写l结尾。
浮点数类型:
char类型:
转移符号还可用于单引号双引号等
布尔类型:
自动类型转换:
在编程过程中,定义long型变量时未加L,默认为int类型,然后通过自动类型转换为long型
定义float型变量时必加f
字符串类型:
强制类型转换:
将容量大的数据类型转换为容量小的数据类型。
整型常量默认为int型
浮点数常量默认为double型
进制:
二进制:0b开头
八进制:0开头
十六进制:0x开头
运算符:
为什么说最高位右移补零或补一,最高位是符号位
三元运算符:
运算符优先级:
break与continue:
break语句用于终止某个语句块;
continue用于跳过所在循环语句块的一次执行,继续下一次循环;
return:当一个语句执行到return语句时,return直接结束整个方法;
scanner输入
具体可参考Javadoc : scanner
数组:
多个相同类型数据按一定顺序排列的集合。
声明:
type var[] 或 type[] var
初始化:
数组长度:arr.length
数组元素默认初始值:
内存的简化结构:
实例分析:
1.首先在堆中创建了一个新的连续空间(new) ,默认初始值为0,0,0
2.初始化f赋值为1,2,3
3.连续空间地址(首元素地址)为0x34ab,栈中arr(位于main方法中,为局部变量)指向该地址。
4.再在堆中创建了一个新的连续空间(new) ,默认初始值为null,null,null,null
5.连续空间地址(首元素地址)为0x12ab,栈中arr1(位于main方法中,为局部变量)指向该地址
6.设置数组第二个元素为刘德华
7.设置数组第三个元素为张学友
8.再在堆中创建了一个新的连续空间(new) ,默认初始值为null,null,null,首地址为0x5566
9.arr1指向地址0x5566
10.不确定的某一时间地址为0x12ab的连续空间被回收
多维数组:
上面注意的意思是int[] y[] 是二维数组
二维数组内存分析:
arrays常见工具类:
面向对象:
对象的内存分析:
属性:
成员变量与局部变量:
方法:
stu.score=(int) (Math.random() *(m-n+1)) //n~m之间的随机数
方法重载:
可变个数的形参:
封装和隐藏:
构造器:
各种赋值方式的先后顺序:
拓展:UML图:
this关键字的使用:
注意:
继承:
注意:Java只支持单继承和多层继承
重写:
四种访问修饰符:
关键字super:
调用父类构造器:
多态性: 父类的引用指向子类的对象
对象的多态性只适用于方法,不适用于属性(编译和运行都看左边)
instanceof: 用于判断向下转型时避免出现classCastException
Casting:强制类型转换
object类:
object类是所有类的父类
object类只声明了一个空参构造器
== 与equals:
==:运算符
1.可以使用在基本数据类型变量中和引用数据类型变量中
2.在基本数据类型中比较两个变量保存的数据是否相等(不一定要数据类型相同)
3.比较的是引用数据类型即比较两个对象的地址值是否相同,即两个引用是否指向同一个对象实体
equals():方法
1.是一个方法而非运算符,只能适用于引用数据类型
2.object类中定义的equals方法同==,比较对象的地址值是否相同
3.像String、Date、File、包装类都重写了object类中的equals()方法,重写以后比较的不是引用地址是否相同,而是比较两个对象的“实体内容”是否相同。
4.通常情况下我们自定义的equals()类希望达到的是比较“实体内容''的效果,我们就需要对object类中的equals()方法进行重写。
toString方法:
包装类(Wrapper):
自动装箱与自动拆箱:
三者间的转换:
关键字static:
静态的,可以用来修饰属性、方法、代码块、内部类
使用static修饰属性,静态变量(类变量) :创建了类的多个对象,多个对象共享同一个静态变量,当通过某一对象修改静态变量时,其他对象的静态变量也变为修改过后的。
(非静态变量(实例属性)):创建了类的多个对象时,每个对象都独立的拥有一套类的非静态属性,每个对象的非静态属性相互独立。
说明:
1.静态变量随着类的加载而加载
2.静态变量的加载要早于对象的创建
3.由于类只会加载一次,静态变量在内存中也只会存在一份,存在方法区的静态域中
-
类变量 实例变量
类 yes no
对象 yes no
静态方法:
随着类的加载而加载,调用可参考如上
静态方法中只能调用静态的方法和属性,非静态方法可以调用非静态属性和方法也可以调用静态属性和方法。(原因:生命周期问题)
在静态的方法内不能使用this关键字、super关键字
单例设计模式:
懒汉式与饿汉式:懒汉式啥时候用是时候造对象,饿汉式(饥渴)早早就造了对象。
代码块:
final修饰属性可以考虑的位置: 1.显式初始化 2.代码块中初始化 3.构造器中初始化
final修饰局部变量:尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参,一旦调用以后就只能在此方法体内使用此形参,但不能进行重新赋值。
抽象类:
接口:
接口与接口之间可以多继承。
创建接口匿名实现类的四种实现方法:
package com.atguigu.java1;
/*
* 接口的使用
* 1.接口使用上也满足多态性
* 2.接口,实际上就是定义了一种规范
* 3.开发中,体会面向接口编程!
*
*/
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferData(flash);
//2. 创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3. 创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
com.transferData(phone);
//4. 创建了接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
代理模式:
public class StaticProxyTest {
public static void main(String[] args) {
Star s = new Proxy(new RealStar());
s.confer();
s.signContract();
s.bookTicket();
s.sing();
s.collectMoney();
}
}
interface Star {
void confer();// 面谈
void signContract();// 签合同
void bookTicket();// 订票
void sing();// 唱歌
void collectMoney();// 收钱
}
//被代理类
class RealStar implements Star {
public void confer() {
}
public void signContract() {
}
public void bookTicket() {
}
public void sing() {
System.out.println("明星:歌唱~~~");
}
public void collectMoney() {
}
}
class Proxy implements Star {
private Star real;
public Proxy(Star real) {
this.real = real;
}
public void confer() {
System.out.println("经纪人面谈");
}
public void signContract() {
System.out.println("经纪人签合同");
}
public void bookTicket() {
System.out.println("经纪人订票");
}
public void sing() {
real.sing();
}
public void collectMoney() {
System.out.println("经纪人收钱");
}
}
/*
经纪人面谈
经纪人签合同
经纪人订票
明星:歌唱~~~
经纪人收钱
*/
面试题:
Java8新特性:
package com.atguigu.java8;
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
// s.method1();
// SubClass.method1();
//知识点1:接口中定义的静态方法,只能通过接口来调用。
CompareA.method1();
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
s.method2();
//知识点3:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,
//那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法。-->类优先原则
//知识点4:如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
//那么在实现类没有重写此方法的情况下,报错。-->接口冲突。
//这就需要我们必须在实现类中重写此方法
s.method3();
}
}
class SubClass extends SuperClass implements CompareA,CompareB{
public void method2(){
System.out.println("SubClass:上海");
}
//知识点四,在没有继承父类superclass的条件下的接口冲突情况,重写method3()
public void method3(){
System.out.println("SubClass:深圳");
}
//知识点5:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
}
内部类:
成员内部类:
package com.atguigu.java2;
/*
* 类的内部成员之五:内部类
* 1. Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
*
* 2.内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
*
* 3.成员内部类:
* 一方面,作为外部类的成员:
* >调用外部类的结构
* >可以被static修饰
* >可以被4种不同的权限修饰
*
* 另一方面,作为一个类:
* > 类内可以定义属性、方法、构造器等
* > 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
* > 可以被abstract修饰
*
*
* 4.关注如下的3个问题
* 4.1 如何实例化成员内部类的对象
* 4.2 如何在成员内部类中区分调用外部类的结构
* 4.3 开发中局部内部类的使用 见《InnerClassTest1.java》
*
*/
public class InnerClassTest {
public static void main(String[] args) {
//创建Dog实例(静态的成员内部类):
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类):
// Person.Bird bird = new Person.Bird();//错误的
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
System.out.println();
bird.display("黄鹂");
}
}
class Person{
String name = "小明";
int age;
public void eat(){
System.out.println("人:吃饭");
}
//静态成员内部类
static class Dog{
String name;
int age;
public void show(){
System.out.println("卡拉是条狗");
// eat();
}
}
//非静态成员内部类
class Bird{
String name = "杜鹃";
public Bird(){
}
public void sing(){
System.out.println("我是一只小小鸟");
Person.this.eat();//调用外部类的非静态属性
eat();
System.out.println(age);
}
public void display(String name){
System.out.println(name);//方法的形参
System.out.println(this.name);//内部类的属性
System.out.println(Person.this.name);//外部类的属性
}
}
public void method(){
//局部内部类
class AA{
}
}
{
//局部内部类
class BB{
}
}
public Person(){
//局部内部类
class CC{
}
}
}
局部内部类:
package com.atguigu.java2;
public class InnerClassTest1 {
//开发中很少见
public void method(){
//局部内部类
class AA{
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
}
异常处理:
runtime Exception类的异常Java可自行捕获,IOException必须使用try catch捕获
package com.atguigu.java1;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.Test;
/*
* 一、异常的处理:抓抛模型
*
* 过程一:"抛":程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。
* 并将此对象抛出。
* 一旦抛出对象以后,其后的代码就不再执行。
*
* 关于异常对象的产生:① 系统自动生成的异常对象
* ② 手动的生成一个异常对象,并抛出(throw)
*
* 过程二:"抓":可以理解为异常的处理方式:① try-catch-finally ② throws
*
*
* 二、try-catch-finally的使用
*
* try{
* //可能出现异常的代码
*
* }catch(异常类型1 变量名1){
* //处理异常的方式1
* }catch(异常类型2 变量名2){
* //处理异常的方式2
* }catch(异常类型3 变量名3){
* //处理异常的方式3
* }
* ....
* finally{
* //一定会执行的代码
* }
*
* 说明:
* 1. finally是可选的。
* 2. 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象
* 的类型,去catch中进行匹配
* 3. 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
* try-catch结构(在没有写finally的情况)。继续执行其后的代码
* 4. catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
* catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错
* 5. 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
* 6. 在try结构中声明的变量,再出了try结构以后,就不能再被调用
* 7. try-catch-finally结构可以嵌套
*
* 体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。
* 相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
*
* 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。
* 针对于编译时异常,我们说一定要考虑异常的处理。
*/
public class ExceptionTest1 {
@Test
public void test2(){
try{
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.print((char)data);
data = fis.read();
}
fis.close();
}catch(FileNotFoundException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
}
@Test
public void test1(){
String str = "123";
str = "abc";
int num = 0;
try{//注意:try里面的语句不表现执行,即不会print
num = Integer.parseInt(str);
System.out.println("hello-----1");
}catch(NumberFormatException e){
// System.out.println("出现数值转换异常了,不要着急....");
//String getMessage():
// System.out.println(e.getMessage());
//printStackTrace():
e.printStackTrace();
}catch(NullPointerException e){
System.out.println("出现空指针异常了,不要着急....");
}catch(Exception e){
System.out.println("出现异常了,不要着急....");
}
System.out.println(num);
System.out.println("hello-----2");
}
}
throws方式:
throws+异常类型写在方法声明处,指明此方法执行时可能抛出的异常类型,一旦当方法体执行时,出现异常,任会在异常代码出生成一个异常类对象,此对象满足throws后的异常类就会抛出,异常代码后续的代码就不再执行。
体会:try-catch-finally:真正的将异常给处理了
throws:没有处理异常,将异常抛给了方法的调用者
方法重写的规则:子类重写的方法异常不大于父类重写的方法异常
package com.atguigu.java1;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 方法重写的规则之一:
* 子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
*
*
*/
public class OverrideTest {
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
test.display(new SubClass());
}
public void display(SuperClass s){
try {
s.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class SuperClass{
public void method() throws IOException{
}
}
class SubClass extends SuperClass{
public void method()throws FileNotFoundException{
}
}
开发中如何选择使用try-catch-finally 还是使用throws?
- 3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。
- 3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的(a执行的方法产生结果x传递给方法b使其能够运行......)。我们建议这几个方法使用throws的方式进行处理(如果用try catch 异常被捕获方法能运行,但后续的方法运行结果错误,无意义)。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
手动抛出异常:
throw
自定义异常类及抛出:
package com.atguigu.java2;
/*
* 如何自定义异常类?
* 1. 继承于现有的异常结构:RuntimeException 、Exception
* 2. 提供全局常量:serialVersionUID
* 3. 提供重载的构造器
*
*/
public class MyException extends Exception{
static final long serialVersionUID = -7034897193246939L;
public MyException(){
}
public MyException(String msg){
super(msg);
}
}
package com.atguigu.java2;
public class StudentTest {
public static void main(String[] args) {
try {
Student s = new Student();
s.regist(-1001);
System.out.println(s);
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
class Student{
private int id;
public void regist(int id) throws Exception {
if(id > 0){
this.id = id;
}else{
// System.out.println("您输入的数据非法!");
//手动抛出异常对象
// throw new RuntimeException("您输入的数据非法!");
// throw new Exception("您输入的数据非法!");
throw new MyException("不能输入负数");
//错误的
// throw new String("不能输入负数");
}
}
@Override
public String toString() {
return "Student [id=" + id + "]";
}
}
package com.atguigu.exer;
//自定义异常类
public class EcDef extends Exception {
static final long serialVersionUID = -33875164229948L;
public EcDef() {
}
public EcDef(String msg) {
super(msg);
}
}
package com.atguigu.exer;
/*
* 编写应用程序EcmDef.java,接收命令行的两个参数,要求不能输入负数,计算两数相除。
对数据类型不一致(NumberFormatException)、缺少命令行参数(ArrayIndexOutOfBoundsException、
除0(ArithmeticException)及输入负数(EcDef 自定义的异常)进行异常处理。
提示:
(1)在主类(EcmDef)中定义异常方法(ecm)完成两数相除功能。
(2)在main()方法中使用异常处理语句进行异常处理。
(3)在程序中,自定义对应输入负数的异常类(EcDef)。
(4)运行时接受参数 java EcmDef 20 10 //args[0]=“20” args[1]=“10”
(5)Interger类的static方法parseInt(String s)将s转换成对应的int值。
如:int a=Interger.parseInt(“314”); //a=314;
*/
public class EcmDef {
public static void main(String[] args) {
try{
int i = Integer.parseInt(args[0]);
int j = Integer.parseInt(args[1]);
int result = ecm(i,j);
System.out.println(result);
}catch(NumberFormatException e){
System.out.println("数据类型不一致");
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("缺少命令行参数");
}catch(ArithmeticException e){
System.out.println("除0");
}catch(EcDef e){
System.out.println(e.getMessage());
}
}
public static int ecm(int i,int j) throws EcDef{
if(i < 0 || j < 0){
throw new EcDef("分子或分母为负数了!");
}
return i / j;
}
}