Java基础语法
★总结:类,方法,构造方法,成员方法,属性,私有属性,局部变量
// Demo类
public class Demo {
public static void main(String[] args) {
foo1(); // 方法
foo2(); // 方法
TempClass t = new TempClass("张三"); // 构造方法,new class时自动调用
t.foo3(); // 调用对象方法(成员方法)
t.age = "20"; // 设置普通age属性
System.out.println(t.age); // 查看设置的age属性
t.setName("林青霞"); // 通过setName设置 私有化的name属性
System.out.println(t.getName()); // 通过getName获取 私有化的name
}
// 不带返回值的方法
public static void foo1(){
return; // 也可以不写return
}
// 带返回值的方法
public static int foo2(int a){
// return 啥数据,static 后面跟什么类型
return a;
}
}
// TempClass类
public class TempClass{
// 成员变量:类中方法外的变量
// 成员变量:会有默认的初始化值(系统自动)
String age; // 普通变量
private String name; // private变量私有化(setter和getter)
// 构造函数
public TempClass(String name) {
this.name = name;
System.out.println("不加参数就是:无参构造方法");
System.out.println("带参构造方法:"+name);
}
// 成员方法:不加static
public void foo3(){
// 局部变量:定义在方法(无论什么方法)中
// 局部变量:没有默认初始化值
String sex = "男";
System.out.println("成员方法被调用");
}
// private私有化变量的setter和getter方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
★需回看内容:
多态
源码很多用到多态,尤其是多态关于成员访问特点。
匿名内部类,lambda表达式
lambda表达式的参数,返回值应用
0 idea代码结构
项目(project)
新建
New Project—>Empty Project—>Next—>添加项目名称和路径
关闭
File—>Close Project
导入
Open—>选择项目文件
模块(module)–对标前端的项目
idea工作区最外层文件夹就是模块的文件夹
新建
File—>Project Structure—>Modules—> + —> New Module
删除
模块文件夹—>右键—>Remove Module—>从工作区删除
模块文件夹—>右键—>Open In—>Explorer—>从磁盘上删除
导入
将模块复制到项目所在路径下
File—>Project Structure—>Modules—> + —> Import Module—> 选择要导入的模块
包(package)–对标前端src下的文件夹
模块里的src下的文件夹就是包的文件夹
新建
src—>New—>Package—>输入包名。包名一般是公司域名反写,并且多级包用.分开
删除
右键—>Delete
使用
包的定义格式,包名一般都是小写。多级包一般用.
分割
格式:package 包名;
导包
格式:import 包名;
手写范例:import com.itheima.Student;
快捷键:Alt+Enter(在类名的代码处)
快捷方式:手写类名时,会有提示,直接Enter确认,会自动导包
类(class)–对标前端vue文件
新建
src—>New—>Java Class—>输入类名。
删除
右键—>Delete
1 数据类型
1.1 基本数据类型(四类八种)
数据类型 | 关键字 | 内存占用 | 取值范围 | 示例 | 说明 |
---|---|---|---|---|---|
整数 | byte | 1 | 负的2的7次方 ~ 2的7次方-1(-128~127) | 666,-88 | 不带小数的数字 |
short | 2 | 负的2的15次方 ~ 2的15次方-1(-32768~32767) | 同上 | 同上 | |
int(常用) | 4 | 负的2的31次方 ~ 2的31次方-1 | 同上 | 同上 | |
long(后缀L) | 8 | 负的2的63次方 ~ 2的63次方-1 | 同上 | 同上 | |
浮点数 | float(后缀F)) | 4 | 1.401298e-45 ~ 3.402823e+38 | 13.14,-5.21 | 带小数的数字 |
double(常用) | 8 | 4.9000000e-324 ~ 1.797693e+308 | 同上 | 同上 | |
字符 | char | 2 | 0-65535 | ‘A’,‘0’, ‘我’ | 必须使用单引号,有且仅能一个字符 |
布尔 | boolean | 1 | true,false | true 、false |
注意点
- 定义long类型的变量,那么在数据值的后面需要加上L后缀。(大小写都可以,建议大写。)
- 定义float类型的变量,那么在数据值的后面需要加上F后缀。(大小写都可以)
1.2 引用数据类型
等面向对象的时候再补充
2 阿里巴巴命名规范(软建议)
小驼峰命名法 | 大驼峰命名法 | |
---|---|---|
后端 | 变量名 | 类名 |
(规范) | 方法名 | |
前端 | 变量名 | 组件名 |
(自定义) | 方法名 |
3 方法
3.1 方法通用格式
public static 返回值类型 方法名(参数) {
方法体;
return 数据;
}
内容 | 释义 |
---|---|
public static | 修饰符,目前先记住这个格式 |
返回值类型 | 方法操作完毕之后,返回的数据类型 |
如果没有返回值,那就写void,并且一般不写return | |
方法名 | 调用方法使用的标识 |
参数 | 由数据类型和变量名组成,多个参数之间用逗号隔开 |
方法体 | 完成功能的代码块 |
return | 有数据返回,通过return返回数据, |
如果没有返回值,返回值类型这里写void,而且一般不写return |
3.2 方法重载
指在
一个类
中定义多个同名的方法
,
但要求每个方法具有不同
的参数的类型
或参数的个数
。
调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。
注意:不看 返回值
的类型
4 对象
4.1 java内存:栈(虚拟机栈)和堆
栈(虚拟机栈):所有局部变量都会在栈内存中创建
局部变量
:定义在方法中的变量或者方法声明上的变量方法
的执行都会加载到栈中执行- 局部变量特点:随着方法的调用而存在,随着方法的结束而消失
堆:所有对象及其对应的成员变量和数组都将存储在此处
- 简单理解:
new出来的东西,都储存在堆内存
- 每个new出来的东西都有一个地址值,使用完毕,会在垃圾回收器空闲时被回收
- 成员变量有
初始化值
- 基本数据类型:
整数:0
- 浮点数:0.0
- 布尔:false
- 字符:空字符
- 引用数据类型:
null
- 基本数据类型:
成员变量和局部变量区别
区别 | 成员变量 |
局部变量 |
---|---|---|
类中位置不同 | 类中方法外 | 方法内或者方法声明上 |
内存中位置不同 | 堆内存 | 栈内存 |
生命周期不同 | 随着对象存在而存在,随着对象消失而消失 | 随着方法调用而存在,随着方法结束而消失 |
初始化值不同 | 有 默认的初始化值 |
没有 默认的初始化值,必须先定义,赋值才能使用 |
4.2.1 关键字:private(封装的表现之一)
private:私有化
- 可以私有化成员变量和成员方法,被
private
修饰的成员只有在本类中才能访问 - 如果需要被其他类使用,提供了2个方法
get变量名()
:用于获取成员变量的值,方法用public
修饰set变量名()
:用于设置成员变量的值,方法用public
修饰
public class StudentDemo {
public static void main(String[] args) {
//创建对象
Student s = new Student();
//给成员变量赋值
s.setName("林青霞"); // 通过setName设置name属性
System.out.println(s.getName()); // 通过getName获取name属性
}
}
public class Student {
//成员变量
private String name; // 变量私有化
// 通过setName提供name属性设置的方法
public void setName(String name) {
// this:代表所在类的对象引用,可以调用本类的成员(属性和方法)
this.name = name;
}
// 通过getName提供name属性获取的方法
public String getName() {
return name;
}
}
4.2.2 关键字:this
- this关键字的作用:
可以调用本类的成员(变量和方法)
, - this:
可以区分局部变量和成员变量的重名问题
- this:代表所在类的对象引用:
方法被哪个对象调用,this就代表哪个对象
4.3 关键字:static
static:静态修饰符
- static 关键字是静态的意思,是Java中的一个修饰符,可以修饰成员方法,成员变量。可以被类的所有对象共享。
类似于前端Vuex
- static修饰的
特点
被类的所有对象共享
,即该类的所有实例都可以访问static修饰的内容。- 是我们判断是否使用静态关键字的条件
随着类的加载而加载,优先于对象存在。
- 对象需要类被加载后,才能创建
可以通过类名调用
,也可以通过对象名调用
- static关键字注意事项
- 静态方法只能访问静态的成员
- 原因:静态随着类的加载而加载,优先于对象存在。非静态需要在创建对象之后,才可以进行使用。也就是静态方法加载的时候,此时对象还没有创建,因此静态方法只能访问静态的成员
- 非静态方法可以访问静态的成员,也可以访问非静态的成员
- 原因:此时类和对象都已经加载完成,不影响访问
- 静态方法中是没有this关键字
- 原因:this 需要在创建对象之后,才会存在,静态存在的时候,对象可能还没有被创建
- 静态方法只能访问静态的成员
Student类
package com.itheima.test;
public class Student {
String name;
int age;
static String school;
/*
静态随着类的加载而加载, 优先于对象存在
非静态需要在创建对象之后,才可以进行使用
1. 静态方法中, 只能访问静态成员(成员变量, 成员方法)
2. 非静态方法中, 可以使用静态成员, 也可以使用非静态成员
3. 静态方法中, 没有this关键字
*/
public void show() {
System.out.println(name + "..." + age + "..." + school);
}
public static void method(){
// this: 当前对象的引用
// this需要在创建对象之后, 才会存在, 静态存在的时候, 对象可能还没有被创建
// this.name = "张三";
System.out.println(school);
}
}
测试类
package com.itheima.test;
public class Test1Static {
/*
1. 被static修饰的成员, 会被该类的所有对象所[共享]
2. 被static修饰的成员, 会随着类的加载而加载, 优先于对象存在
3. 多了一种调用方式, 可以通过类名.进行调用
*/
public static void main(String[] args) {
Student.school = "传智专修学院";
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 23;
//stu1.school = "传智专修学院";
stu1.show();
Student stu2 = new Student();
stu2.show();
//调用静态方法
Student.method();
}
}
4.4 关键字:extends
extends:继承
- 继承的概念
- 继承是面向对象三大特征之一,可以使得
子类直接使用父类
的非私有
属性和方法,还可以在子类中重新定义,以及追加属性和方法
- 继承是面向对象三大特征之一,可以使得
- 实现继承的格式
- 格式:
public class 子类 extends 父类 { }
- 举例:
public class Dog extends Animal { }
- 格式:
- 方法重写的应用场景:
- 当子类需要父类的功能,而功能主体子类有自己特有内容
- 可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
- 继承的
方法重写
:- 在
继承体系
中,子类出现和父类一模一样的方法声明(方法名,参数列表,返回值类型都相同
)- 父类中
私有方法不能被重写
静态方法不能被重写!
如果真存在,可以理解为,子类将父类中同名的方法,隐藏了起来,并非是方法重写!父类非静态方法
,子类也必须通过非静态方法进行重写
- 子类重写父类方法时,
访问权限必须大于等于父类
- 父类中
方法重载
:在同一个类中,方法名相同,参数列表不同,与返回值无关。
- 在
public class Fu {
public void show() {
System.out.println("show方法被调用");
}
}
public class Zi extends Fu {
public void method() {
System.out.println("method方法被调用");
}
}
public class Demo {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
z.show();
}
}
4.5 构造方法
有点像js的constructor,类被实例化时,会自动调用该构造函数进行初始化。
格式:
1.方法名与类名相同,大小写也要一致
2. 没有返回值类型,连void都没有
3. 没有具体的返回值(不能由retrun带回结果数据)
public class 类名{
修饰符 类名( 参数 ) {
}
}
public class Student {
private String name;
private int age;
//构造方法
// public Student() {
// System.out.println("无参构造方法");
// }
// 构造方法的重载,
// 当自定义了构造方法时,系统就不会自动创建无参构造方法,需要手动创建
public Student() {}
public Student(String name) {
this.name = name;
}
public Student(int age) {
this.age = age;
}
public Student(String name,int age) {
this.name = name;
this.age = age;
}
public void show() {
System.out.println(name + "," + age);
}
}
public class StudentDemo {
public static void main(String[] args) {
Student s1 = new Student();
s1.show();
//public Student(String name)
Student s2 = new Student("林青霞");
s2.show();
//public Student(int age)
Student s3 = new Student(30);
s3.show();
//public Student(String name,int age)
Student s4 = new Student("林青霞",30);
s4.show();
}
}
4.6 JavaBean
标准JavaBean须满足以下要求:
- 成员变量使用private修饰
- 提供每一个成员变量对应的setXX()、getXX()
- 提供一个无参构造函数
使用:
- 鼠标右键,选择Generate(生成),快捷键:Alt+Insert
- Constructor:用于生成构造方法
- Getter and Setter :用于生成private的调用方法
- toString:重写这个方法,用于将print(对象)输出地址改为输出对象信息
/*
Alt+Insert(Fn) 根据自己的选择,生成想要的内容
private 成员变量需要自己写
*/
public class Phone {
private String brand;
private int price;
public Phone() {
}
public Phone(String brand, int price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public String toString() {
return "Student{" +
"brand='" + brand+ '\'' +
'}';
}
}
4.7 抽象类:abstract
抽象类的概述(理解)
当我们在做子类共性功能抽取时,有些方法在父类中并没有具体的体现,这个时候就需要抽象类了!
在Java中,一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类!
个人理解:抽象类就是提取共性功能到一个类(抽象类)中,个性功能在这个类中,写成抽象方法进行占位,等后续子类继承的时候进行方法重写。
抽象类的特点(记忆)
-
抽象类和抽象方法必须使用
abstract
关键字修饰//抽象类的定义 public abstract class 类名 {} //抽象方法的定义 public abstract void eat();
-
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
-
抽象类不能实例化
-
抽象类可以有构造方法
-
抽象类的子类
要么重写抽象类中的所有抽象方法
要么是抽象类
模板设计模式
-
模板设计模式
把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法
让使用模板的类(继承抽象类的类)去重写抽象方法实现需求
个人理解:以抽象类封装所有逻辑(通用+个性功能),个性功能定义成抽象方法,等子类继承时进行重写
-
模板设计模式的优势
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可
-
示例代码
模板类
/* 作文模板类 */ public abstract class CompositionTemplate { public final void write(){ System.out.println("<<我的爸爸>>"); body(); System.out.println("啊~ 这就是我的爸爸"); } public abstract void body(); }
实现类A
public class Tom extends CompositionTemplate { @Override public void body() { System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " + "那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬..."); } }
实现类B
public class Tony extends CompositionTemplate { @Override public void body() { } /*public void write(){ }*/ }
测试类
public class Test { public static void main(String[] args) { Tom t = new Tom(); t.write(); } }
4.8 关键字:final
-
fianl关键字的作用
- final代表最终的意思,可以修饰成员方法,成员变量,类
-
final修饰类、方法、变量的效果
-
fianl修饰类:该类不能被继承(不能有子类,但是可以有父类)
-
final修饰方法:该方法不能被重写
-
final修饰变量:表明该变量是一个常量,不能再次赋值
-
变量是基本类型,不能改变的是值
-
变量是引用类型,不能改变的是地址值,但地址里面的内容是可以改变的
-
举例
public static void main(String[] args){ final Student s = new Student(23); s = new Student(24); // 错误 s.setAge(24); // 正确 }
-
-
4.9 代码块
1代码块概述 (理解)
在Java中,使用 { } 括起来的代码被称为代码块
2代码块分类 (理解)
-
局部代码块
-
位置: 方法中定义
-
作用: 限定变量的生命周期,及早释放,提高内存利用率
-
示例代码
public class Test { /* 局部代码块 位置:方法中定义 作用:限定变量的生命周期,及早释放,提高内存利用率 */ public static void main(String[] args) { { int a = 10; System.out.println(a); } // System.out.println(a); } }
-
-
构造代码块
-
位置: 类中方法外定义
-
特点: 每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
-
作用: 将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
-
示例代码
public class Test { /* 构造代码块: 位置:类中方法外定义 特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性 */ public static void main(String[] args) { Student stu1 = new Student(); Student stu2 = new Student(10); } } class Student { { System.out.println("好好学习"); } public Student(){ System.out.println("空参数构造方法"); } public Student(int a){ System.out.println("带参数构造方法..........."); } }
-
-
静态代码块
-
位置: 类中方法外定义
-
特点: 需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
-
作用: 在类加载的时候做一些数据初始化的操作
-
示例代码
public class Test { /* 静态代码块: 位置:类中方法外定义 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次 作用:在类加载的时候做一些数据初始化的操作 */ public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(10); } } class Person { static { System.out.println("我是静态代码块, 我执行了"); } public Person(){ System.out.println("我是Person类的空参数构造方法"); } public Person(int a){ System.out.println("我是Person类的带...........参数构造方法"); } }
-
5 接口
1 接口的概述(理解)
- 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
- Java中接口存在的两个意义
- 用来
定义
规范 - 用来做功能的
拓展
- 用来
2 接口的特点(记忆)
-
接口用关键字
interface
修饰public interface 接口名 {}
-
类实现接口用
implements
表示public class 类名 implements 接口名 {}
-
接口不能实例化
我们可以创建接口的实现类对象使用
-
接口的子类
要么重写接口中的所有抽象方法
要么子类也是抽象类
3 接口的成员特点(记忆)
-
成员特点
-
成员变量
只能是常量
默认修饰符:public static final -
构造方法
没有,因为接口主要是扩展功能的,而没有具体存在
-
成员方法
只能是抽象方法
默认修饰符:public abstract
关于接口中的方法,JDK8和JDK9中有一些新特性,后面再讲解
-
-
代码演示
- 接口
public interface Inter { public static final int NUM = 10; public abstract void show(); }
- 实现类
class InterImpl implements Inter{ public void method(){ // NUM = 20; System.out.println(NUM); } public void show(){ } }
- 测试类
public class TestInterface { /* 成员变量: 只能是常量 系统会默认加入三个关键字 public static final 构造方法: 没有 成员方法: 只能是抽象方法, 系统会默认加入两个关键字 public abstract */ public static void main(String[] args) { System.out.println(Inter.NUM); } }
4 类和接口的关系(记忆)
-
类与类的关系
继承关系,只能单继承,但是可以多层继承
-
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
-
接口与接口的关系
继承关系,可以单继承,也可以多继承
5 接口中默认方法【应用】
- 格式
public default 返回值类型 方法名(参数列表) { }
-
作用
解决接口升级的问题。允许接口中定义带有方法体的方法。
-
范例
public default void show3() { }
-
注意事项
- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
- public可以省略,default不能省略
- 如果实现了多个接口,多个接口中存在相同的方法声明,子类就必须对该方法进行重写
6 接口中静态方法【应用】
-
格式
public static 返回值类型 方法名(参数列表) { }
-
范例
用
static
替换了接口的default
关键字public static void show() { }
-
注意事项
- 静态方法只能通过
接口名
调用,不能通过实现类名或者对象名调用 - public可以省略,static不能省略
- 静态方法只能通过
7 接口中私有方法【应用】
-
私有方法产生原因
Java 9中新增了带方法体的私有方法,这其实在Java 8中就埋下了伏笔:Java 8允许在接口中定义带方法体的默认方法和静态方法。这样可能就会引发一个问题:当两个默认方法或者静态方法中包含一段相同的代码实现时,程序必然考虑将这段实现代码抽取成一个共性方法,而这个共性方法是不需要让别人使用的,因此用私有给隐藏起来,这就是Java 9增加私有方法的必然性
-
定义格式
-
格式1
private 返回值类型 方法名(参数列表) { }
-
范例1
private void show() { }
-
格式2
private static 返回值类型 方法名(参数列表) { }
-
范例2
private static void method() { }
-
-
注意事项
- 默认方法可以调用私有的静态方法和非静态方法
- 静态方法只能调用私有的静态方法
6 多态
1 多态的概述(记忆)
-
什么是多态
同一个对象,在不同时刻表现出来的不同形态
-
多态的前提
- 要有继承或实现关系
- 要有方法的重写
- 要有父类引用指向子类对象
-
个人理解:
把原来某个对象类型(子类)通过参数传入,返回值类型用父类的(子类与父类有继承/实现关系)。父类中定义抽象方法,子类重写抽象方法。
说白了就是:对象当参,对象再提取一层。
-
代码演示
class Animal { public void eat(){ System.out.println("动物吃饭"); } } class Cat extends Animal { @Override public void eat() { System.out.println("猫吃鱼"); } } public class Test1Polymorphic { /* 多态的前提: 1. 要有(继承 \ 实现)关系 2. 要有方法重写 3. 要有父类引用, 指向子类对象 */ public static void main(String[] args) { // 当前事物, 是一只猫 Cat c = new Cat(); // 当前事物, 是一只动物 Animal a = new Cat(); a.eat(); } }
2 多态中的成员访问特点(记忆)
-
成员访问特点
-
成员变量
编译看父类,运行看父类
-
成员方法
编译看父类,
运行看子类
-
-
代码演示
class Fu { int num = 10; public void method(){ System.out.println("Fu.. method"); } } class Zi extends Fu { int num = 20; public void method(){ System.out.println("Zi.. method"); } } public class Test2Polymorpic { /* 多态的成员访问特点: 成员变量: 编译看左边 (父类), 运行看左边 (父类) 成员方法: 编译看左边 (父类), 运行看右边 (子类) */ public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.num); f.method(); } }
3 多态的好处和弊端(记忆)
-
好处
提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
-
弊端
不能使用子类的特有成员
-
弊端解决方案:
1. 直接重新new 一个子类对象,通过子类对象.方法来使用
2. 通过多态的转型,把父类型强制转回子类型
4 多态中的转型(应用)
-
向上转型
父类引用指向子类对象就是向上转型
-
向下转型
格式:子类型 对象名 = (子类型)父类引用;
-
代码演示
class Fu { public void show(){ System.out.println("Fu..show..."); } } class Zi extends Fu { @Override public void show() { System.out.println("Zi..show..."); } public void method(){ System.out.println("我是子类特有的方法, method"); } } public class Test3Polymorpic { public static void main(String[] args) { // 1. 向上转型 : 父类引用指向子类对象 Fu f = new Zi(); f.show(); // 多态的弊端: 不能调用子类特有的成员 // f.method(); // A: 直接创建子类对象 // B: 向下转型 // 2. 向下转型 : 从父类类型, 转换回子类类型 Zi z = (Zi) f; z.method(); } }
5 多态中转型存在的风险和解决方案 (应用)
-
风险
如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException
-
解决方案
-
关键字
instanceof
-
使用格式
变量名 instanceof 类型
通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
-
-
代码演示
abstract class Animal { public abstract void eat(); } class Dog extends Animal { public void eat() { System.out.println("狗吃肉"); } public void watchHome(){ System.out.println("看家"); } } class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } } public class Test4Polymorpic { public static void main(String[] args) { useAnimal(new Dog()); useAnimal(new Cat()); } public static void useAnimal(Animal a){ // Animal a = new Dog(); // Animal a = new Cat(); a.eat(); //a.watchHome(); // Dog dog = (Dog) a; // dog.watchHome(); // ClassCastException 类型转换异常 // 判断a变量记录的类型, 是否是Dog if(a instanceof Dog){ Dog dog = (Dog) a; dog.watchHome(); } } }
7 数组和集合arraylist
1 数组定义
静态初始化
开始就存入元素值,适合一开始就能确定元素值的业务场景
格式:数据类型[] 变量名 = {};
例如:int[] arr = {77,88,99};
动态初始化
指定数组长度,后期赋值,适合开始知道数据的数量,但是不确定具体元素值的业务场景
格式:数据类型[] 变量名 = new 数据类型[数组长度];
例如:int[] arr = new int[3];
2 数组常用方法
长度:arr.length
循环:arr.fori
(idea的快捷键)
循环语句别名:for循环外加上【别名:】
退出指定循环:break 别名;
wc:for (int i = 0; i < arr.length; i++) {
if (arr[0]==88){
break wc;
}
}
3 二维数组
二维数组:元素为一维数组的数组
二维数组定义
数据类型[][] 变量名; int[][] arr;
静态初始化
格式:数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…},…};
范例:int[][] arr = new int[][]{{1,2,3},{4,5,6},{7,8,9}};
简化格式:数据类型[][] 变量名 = {{元素…},{元素…},{元素…},…};
范例:int[][] arr = {{1,2,3},{4,5,6},{7,8,9}};
动态初始化
格式:数据类型[][] 变量名 = new 数据类型[m][n];
范例:int[][] arr = new int[2][3];
4 集合(arraylist)和数组的区别,
1、数组的长度是不可变的,集合的长度是可变的。
集合才像是js的list,
2、数组
可以存基本
数据类型和引用
数据类型。
集合
只能存引用
数据类型,如果要存基本数据类型,需要存对应的包装类
。
5 集合定义:构造函数
ArrayList<String> array = new ArrayList<String>();
注意
ArrayList<E>
的<E>
:是一种特殊的数据类型,泛型
。
6 集合示例代码
public class ArrayListDemo02 {
public static void main(String[] args) {
//创建集合
ArrayList<String> array = new ArrayList<String>();
//添加元素
array.add("hello");
array.add("world");
array.add("java");
//public boolean remove(Object o):删除指定的元素,返回删除是否成功
// System.out.println(array.remove("world"));
// System.out.println(array.remove("javaee"));
//public E remove(int index):删除指定索引处的元素,返回被删除的元素
// System.out.println(array.remove(1));
// 集合删除某一类特定元素,例如删除集合内所有的test字符串,用for循环遍历后,
// 判断是否包含,如果是就进行remove操作,
// 关键点:此时需要进行i--
// (原因:集合删除元素后,前面的位置不会空着,而是所有元素前置补充,因此删除后需要再从当前索引继续操作)
//IndexOutOfBoundsException
// System.out.println(array.remove(3));
//public E set(int index,E element):修改指定索引处的元素,返回被修改的元素
// System.out.println(array.set(1,"javaee"));
//IndexOutOfBoundsException
// System.out.println(array.set(3,"javaee"));
//public E get(int index):返回指定索引处的元素
// System.out.println(array.get(0));
// System.out.println(array.get(1));
// System.out.println(array.get(2));
//System.out.println(array.get(3)); //?????? 自己测试
//public int size():返回集合中的元素的个数
System.out.println(array.size());
//输出集合
System.out.println("array:" + array);
}
}
8 内部类(了解)
8.1 定义
内部类:就是在一个类中定义一个类。举例:在一个A类的内部定义一个B类, B类就被称为内部类
8.2 语法
1、按照内部类在类中定义的位置不同,可以分为如下两种形式
- 在类的成员位置:成员内部类
- 在类的局部位置:局部内部类
2、成员内部类,外界如何创建对象使用呢?
- 格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象;
- 范例:
Outer.Inner oi = new Outer().new Inner();
8.3 成员内部类
成员内部类,也属于(成员),既然是成员就可以被一些修饰符所修饰
- private:
- 私有成员内部类访问:在自己所在的外部类中创建对象访问。
- static:
- 静态成员内部类访问格式:外部类名.内部类名 对象名 = new 外部类名.内部类名();
- 静态成员内部类中的静态方法:外部类名.内部类名.方法名();
8.4 匿名内部类
概述:匿名内部类本质上是一个特殊的局部内部类(定义在方法内部)
前提:需要存在一个接口或类
格式:
new 类名或者接口名() {
重写方法;
};
示例:
// new 接口
new Inter() {
// 重写接口的方法
public void show() {
}
}.show() // 调用重写的方法
理解:匿名内部类是将(继承 \ 实现)(方法重写)(创建对象)三个步骤,放在了一步进行。简化了常规的类实现的过程
注意:如果接口中有2个方法,调用方法跟new对象赋值类似
// 这是个多态,接口(父类) = new 子类
Inter i = new Inter() {
public void show1() {
}
public void show2() {
}
}
i.show1()
i.show2()
开发中应用:
当方法的形式参数是接口或者抽象类
时,可以将匿名内部类作为实际参数进行传递。
/*
游泳接口
*/
public interface Swimming {
void swim();
}
/*
测试类
*/
public class JumppingDemo {
public static void main(String[] args) {
//需求:goSwimming方法
}
// goSwimming方法的参数需要Swimming 接口的实现类,可以采用匿名内部类的写法
public static void goSwimming(Swimming swimming) {
swimming.swim();
}
}
9 Lambda表达式:类似于前端的箭头函数
9.1 Lambda表达式的格式
- 格式:
( 形式参数 ) -> { 代码块 }
- 形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
- ->:由英文中画线和大于符号组成,固定写法。代表指向动作
- 代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
9.2 Lambda表达式的使用前提
- 有一个
接口
- 接口中
有且仅有一个抽象方法
- 理解:
lambda表达式,对匿名内部类进行了优化
9.3 Lambda表达式和匿名内部类的区别
-
所需类型不同
- 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
- Lambda表达式:只能是接口
-
使用限制不同
- 如果接口中有且仅有一个抽象方法,可以使用Lambda表达式,也可以使用匿名内部类
- 如果接口中多于一个抽象方法,只能使用匿名内部类,而不能使用Lambda表达式
-
实现原理不同
- 匿名内部类:编译之后,产生一个单独的.class字节码文件
- Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
10 API基本使用
10.1 帮助手册的使用1.6版本
① 打开帮助文档
② 找到索引选项,输入要学习的类,然后回车,再回车
③ 看类所在包: 类上面的代码,例如:java.lang
— java.lang
包下的类在使用的时候不需要导包
④ 看类的描述:类是干什么的
⑤ 看类的构造方法:创建对象使用
⑥ 看类的成员方法:完成功能使用
10.2 注意
静态
的方法和变量是可以通过类名访问
的。即可以写成:类名.方法
/类名.属性
- 判断是否是静态的方法或变量?
- 带着static的就是静态方法
10.3 基本类型包装类
大部分是包装类和基本数据类型的类名一致,只是首字母改成 大写
。
特殊的有2个:Integer(int)和Character(char)
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
10.4 Integer包装类
- 自动装箱:把基本数据类型转换为对应的包装类类型,
- 自动:其实就是Java底层会帮我们自动的调用valueof方法。
- 自动拆箱:把包装类类型转换为对应的基本数据类型。
- 示例:
Integer i1 = 100 // 自动装箱 int i2 = i1 // 自动拆箱
10.5 数组的高级操作:手写二分查找
二分查找的步骤:前提是有序的数组
1、 定义两个变量,表示要查找的范围。默认min = 0 , max = 最大索引
2、循环查找,但是min <= max
3、计算出mid的值
4、判断mid位置的元素是否为要查找的元素,如果是直接返回对应索引
5、如果要查找的值在mid的左半边,那么min值不变,max = mid -1.继续下次循环查找
6、如果要查找的值在mid的右半边,那么max值不变,min = mid + 1.继续下次循环查找
7、当 min > max 时,表示要查找的元素在数组中不存在,返回-1.
private static int binarySearchForIndex(int[] arr, int number) {
//1,定义查找的范围
int min = 0;
int max = arr.length - 1;
//2.循环查找 min <= max
while(min <= max){
//3.计算出中间位置 mid
int mid = (min + max) / 2;
//mid指向的元素 > number
if(arr[mid] > number){
//表示要查找的元素在左边.
max = mid -1;
}else if(arr[mid] < number){
//mid指向的元素 < number
//表示要查找的元素在右边.
min = mid + 1;
}else{
//mid指向的元素 == number
return mid;
}
}
//如果min大于了max就表示元素不存在,返回-1.
return -1;
}
10.5 数组的高级操作:手写冒泡排序
冒泡排序的步骤:
如果有n个数据进行排序,总共需要比较n-1次
每一次比较完毕,下一次的比较就会少一个数据参与
1,相邻的元素两两比较,大的放右边,小的放左边,找到最大值。
2,第一次循环结束,最大值5已经找到,在数组的最右边。
3,下一次只要在剩余的元素(1,2,3,4)找最大值就可以了。
4,第二轮:当比较到4的时候,因为上一轮已经确定了5是最大值,所以4跟5无须再进行比较了。
5,第三轮:当比较到3的时候,因为上一轮已经确定了5是最大值,4是次大值。所以3无须跟4和5再进行比较了。
6,第四轮:同理3,4,5的位置已经确定了,2也无须这三个值进行比较了
7,第五轮:最后只剩下一个值1了,肯定就放在最后一个格子中
private static void bubbleSort(int[] arr) {
//外层循环控制的是次数 比数组的长度少一次.
for (int i = 0; i < arr.length -1; i++) {
//内存循环就是实际循环比较的
//-1 是为了让数组不要越界
//-i 每一轮结束之后,我们就会少比一个数字.
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
printArr(arr);
}
11 异常
11.1 异常体系
11.2 异常处理逻辑
public static void main(String[] args){
int [] arr = {1,2,3,4,5};
System.out.println(arr[10]); // 当代码出现了异常,那么就在这里创建了一个异常对象.
System.out.println("嘿嘿嘿,我最帅");
}
- 首先会看,程序中有没有
自己处理异常的代码.
- 如果
没有
,交给本方法的调用者处理.
最终
这个异常会交给虚拟机默认处理.
- 将异常信息以
红色字体展示
在控制台上. 停止程序运行
. — 哪里出现了异常,那么程序就在哪里停止,下面的代码不执行了.
- 将异常信息以
11.3 抛出:异常对象1:throws
格式:throws 异常类名;
注意:这个格式是写在方法的定义处
,表示声明一个异常。
示例
public static void main(String[] args) throws ParseException {
method1(); //此时调用者也没有处理.还是会交给虚拟机处理.
method2(); //还是继续交给调用者处理.而main方法的调用者是虚拟机还是会采取虚拟机默认处理异常的方法.
}
//告诉调用者,你调用我,有可能会出现这样的异常哦.
//如果方法中没有出现异常,那么正常执行
//如果方法中真的出现了异常,其实也是将这个异常交给了调用者处理.
//如果声明的异常是一个运行时异常,那么声明的代码可以省略
private static void method1() /*throws NullPointerException*/ {
int [] arr = null;
for (int i = 0; i < arr.length; i++) {//出现的空指针异常,还是由虚拟机创建出来的.
System.out.println(arr[i]);
}
}
//如果声明的异常是一个编译时异常,那么声明的代码必须要手动写出.
private static void method2() throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
sdf.parse("2048-10月10日");
}
★11.4 抛出:异常对象2 : throw
格式:throw new 异常();
注意:这个格式是在方法内
的,表示当前代码手动抛出一个异常,下面的代码不用再执行了。
意义
1、在方法中,当传递的参数有误,没有继续运行下去的意义了,则采取抛出处理,表示让该方法结束运行。
2、告诉调用者方法中出现了问题。
示例
public static void main(String[] args) {
int [] arr = null;
printArr(arr);//就会 接收到一个异常。如果调用者没有处理就会由JVM处理。
}
private static void printArr(int[] arr) {
if(arr == null){
throw new NullPointerException(); //当参数为null的时候
//手动创建了一个异常对象,抛给了调用者.
}else{
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
11.5 throws 和 throw 的区别
throws | throw |
---|---|
用在方法声明后面 ,跟的是异常类名 |
用在方法体内 ,跟的是异常对象名 |
表示声明异常 ,调用该方法有可能会出现这样的异常 |
表示手动抛出 异常对象,由方法体内的语句处理 |
★11.6 捕获:异常处理:try…catch…
格式
// 多个异常,可以写多个catch进行捕获
try {
可能出现异常的代码;
} catch(异常类名 异常变量名) {
异常的处理代码;
} finally {
无论是否有异常,都一定会执行的代码;
}
示例
public static void main(String[] args) {
try {
int [] arr = {1,2,3,4,5};
System.out.println(arr[10]);//虚拟机帮我们创建了一个异常对象 new ArrayIndexOutOfBoundsException();
} catch (ArrayIndexOutOfBoundsException e) {
// e 就是捕获到的异常对象,这里是ArrayIndexOutOfBoundsException对象
e.printStackTrace();
}
System.out.println("嘿嘿嘿");
}
实际开发应用
// 定义在Student类中的set方法中进行抛出异常
// Student.class
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
throw new RuntimeException("年龄超出了范围");
}
}
// 在调用方法处,进行捕获异常
try {
int age = Integer.parseInt(ageStr);
s.setAge(age); // 从这里开始捕获异常
break;
} catch (RuntimeExceptione e) {
System.out.println(e.printStackTrace());
System.out.println("请输入一个符合范围的年龄");
continue; // 跳过当前的循环,进入下一个循环
}
★11.7 自定义异常处理
定义:自定义异常
// CustomException 可以见名知意的修改成其他名称
public class CustomException extends RuntimeException {
// Alt + Insert 快速生成构建方法
public CustomException() {
}
public CustomException(String message) {
super(message);
}
}
抛出:自定义异常
public void setAge(int age) {
if(age >= 18 && age <= 25){
this.age = age;
}else{
// 抛出异常时,选择new 自定义异常对象
throw new CustomException ("年龄超出了范围");
}
}
捕获:自定义异常
try {
int age = Integer.parseInt(ageStr);
s.setAge(age); // 从这里开始捕获异常
break;
} catch (CustomException e) { // 捕获自定义异常
System.out.println(e.printStackTrace());
System.out.println("请输入一个符合范围的年龄");
continue; // 跳过当前的循环,进入下一个循环
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/84940.html