Java读入
/*
1. 导包:import java.util.Scanner
2. 实例化:Scanner scan = new Scanner(System.in);
3. 调用Scanner类的相关方法(next() / nextXxx()),来获取指定类型的变量
nextDouble、nextInt、next、nextboolean
*/
import java.util.Scanner;
class ScannerTest{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int num = scan.nextInt();
String name = scan.next();
double weight = scan.nextDouble();
System.out.println(num);
}
}
读入字符
import java.util.Scanner;
class ScannerChar{
public static void main(String []args){
Scanner scan = new Scanner(System.in);
String str = scan.next();
char c = str.charAt(0);
}
}
switch case 语句
/*
switch-case
1. 格式
switch(表达式){
case 常量1:
执行语句1;
// break;
case 常量2:
执行语句2;
// break;
...
default:
执行语句n;
// break;
}
2. 说明
根据switch表达式中的值,依次匹配各个case中的常量,一旦匹配成功,则进入相应case结构中,调用其执行语句。当调用执行语句以后,则仍然继续向下执行其他case结构中的执行语句,直到遇到break关键字或此switch-case结构末尾结束为止。
*/
continue+标签
label: for (int i = 1; i <= 4; ++i){
for (int j = 1; j <= 10; ++j){
if (j % 4 == 0)
continue lable;
System.out.print(j);
}
System.out.println();
}
// 正确输出为123123123123
数组
声明和初始化
package contact;
public class HelloWorld {
public static void main(String[] args) {
// 声明和初始化
int[] ids = new int[] {1001,1002,1003,1004};
String[] names = new String[5];
// 获取数组的长度
System.out.println(names.length);
// 遍历数组长度
for (int i = 0; i < names.length; ++i) {
System.out.println(names[i]);
}
// 数组元素的默认初始化值
/* 数组的(整型)默认初始化值为0
* 数组的(布尔型)默认初始化值为false
* 数组的(char型)默认初始化值为ASCII为0
* 数组的(浮点型)默认初始化值为0.0
* 数组的(String型)默认初始化值为null
*/
// 二维数组的声明和初始化
// 静态初始化
int[][] arr1 = new int[][] {{1,2,3},{4,5},{6,7,8}};
// 动态初始化
String[][] arr2 = new String[3][2];
double[][] d = new double[4][];
/*
* 二维数组的使用:
* 规定: 二维数组分为外层数组的元素,内层数组的元素
* int[][] arr = new int[4][3];
* 外层元素:arr[0], arr[1]等
* 内层元素:arr[0][0], arr[0][1]等
*
* 数组元素的默认初始化值
* 针对于初始化方式一:比如 int[][] arr = new int[4][3];
* 外层元素的初始化值为:地址值
* 内层元素的初始化值为:元素默认值
* 针对于初始化方式二:比如 int[][] arr = new int[4][];
* 外层元素的初始化值为:null
* 内层元素的初始化值为,不能调用,否则报错
*
*/
}
}
面向对象
面向对象的三大特征:封装性,继承性,多态性、(抽象性)
可变个数形参的方法
- 可变个数形参的格式:数据类型 … 变量名
- 当调用可变个数形参的方法时,传入的参数的个数可以是:0个,1个,2个,…
- 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载
- 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存
- 可变个数形参在方法的形参中,必须声明在末尾
- 可变个数形参在方法的形参中,最多只能声明一个可变形参
public class MethodArgsTest {
public static void main(String[] args) {
MethodArgsTest test = new MethodArgsTest();
test.show("hello");
test.show("hello", "world");
test.show();
}
public void show(int i) {
}
public void show(String s) {
}
public void show(String ... strs) {
System.out.println("1111");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
// public void show(String[] strs) {
//
// }
}
方法参数的值传递机制
关于变量的赋值
如果变量是基本数据类型 ,赋值的是变量实际存储的数据值。
如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
方法的形参传递机制:值传递
- 形参:方法定义时,声明的小括号内的参数
实参:方法调用时,实际传递给形参的数据 - 值传递机制
如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
如果参数是引用对象类型,此时实参赋给形参的是实参的地址
四种访问权限修饰符
修饰类只能用public和缺省
构造器(或构造方法、constructor)的使用
- 如果没有显式的定义类的构造器的话,则系统默认提供一个空参的构造器
- 定义构造器的格式:权限修饰符 类名(形参列表){}
- 一个类中定义的多个构造器,彼此构成重载
- 一旦我们显式的定义了类的构造器之后,系统就不再提供默认的空参构造器
- 一个类中,至少有一个构造器
this的使用
-
this 可以用来修饰:属性、方法、构造器
-
this修饰属性和方法:
this理解为:当前对象在类的方法中,我们可以使用"this.属性"或"this.方法"的方式,调用当前对象属性或方法。但是,通常情况下,我们都省略"this."。如果方法的形参和类的属性同名时,我们必须显式的使用"this.变量"的方式,表明此变量是属性,而非形参。
-
this构造器
我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器。
构造器中不能通过"this(形参列表)"方式调用自己。
规定:"this(形参列表)“必须声明在当前构造器的首行
构造器内部,最多只能声明一个"this(形参列表)”,用来调用其他的构造器
package, import
package
- 使用package声明类或接口所属的包,声明在源文件的首行
- 每"."一次,就是一层文件目录
import
- 在源文件中显式的使用import结构导入指定包下的类、接口。
- 声明在包的声明和类的声明之间。
- 如果需要导入多个结构,则并列写出即可
- 可以使用"xxx.*"的方式,表示导入xxx包下的所有结构
- 定义在lang下的类或接口,则可以省略。
- 如果使用的类或接口是本包下定义的,则可以省略import结构
- 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要使用全类名的方式显示。
- 如果使用"xxx.*"方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式定义。
- import static: 导入指定类或接口中的静态结构:属性或方法。
继承
继承性的格式:class A extends B {}
A:子类、派生类、subclass
B:父类、超类、基类、superclass
体现:一旦子类继承父类B以后,子类A中就获取了父类B中声明所有的属性和方法。
特别的:父类中声明为private的属性或方法,子类继承父类以后,仍然认为获取了父类中私有的结构。只是因为封装性的影响,使得子类不能直接调用父类的结构。
子类继承父类以后,还可以声明自己特有的属性或方法:实现功能的拓展。
方法的重写
-
重写:子类继承父类以后,可以对父类中同名同参数的方法,进行覆盖操作
-
应用:重写以后,当创建子类对象以后,通过子类对象调用子父类中的同名同参数的方法时,实际执行的是子类重写父类的方法。
-
重写的规定:
子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同
子类重写的方法权限修饰符不小于父类被重写的方法的权限修饰符子类不能重写父类中权限修饰符为private的方法
返回值类型:
父类被重写的方法的返回值类型是void,则子类重写的方法的返回值只能是void
父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
super关键字
super的使用:调用属性和方法
- 可以在子类的方法或构造器中,通过使用"super.属性"或"super.方法"的方式,显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."
- 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
- 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。
super构造器
- 我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
- "super(形参列表)"的使用,必须声明在子类构造器的首行!
- 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)"只能二选一,不能同时出现
- 在构造器的首行,没有显式的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器
- 在类的构造器中,至少有一个类的构造器使用了"super(形参列表)",调用父类中的构造器
子类继承父类以后,就获取了父类中声明的属性或方法。
创建子类的对象,在堆空间中,就会加载所有父类声明的属性。
当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用父类的构造器,进而调用父类的构造器直到调用了java.lang.Object类中的空参的为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类中的结构,子类对象才可以考虑进行调用
虽然创建子类对象时,调用了父类的构造器。但自始至终就创建过一个对象,即为new的子类对象
多态性
-
对象的多态性:父类的引用指向子类的对象
-
多态的使用:虚拟方法的调用
有了对象的多态性以后,我们在编译器,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法。 -
总结:编译看左边,运行看右边。
-
多态性的使用前提:①类的继承关系②方法的重写
-
对象的多态性,只适用于方法,不适用于属性
子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类的方法称为虚拟方法,父类根据赋给他的不同子类对象,动态调用属于子类的该方法。这样的方法调用在编译期是无法确定的。
有了对象的多态以后,内存中实际上是加载了子类特有的属性和方法的。但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。
如何才能调用子类特有的属性和方法?
向下转型:使用强制类型转换符
Man是Person的一个子类
Person p2 = new Man();
Man m1 = (Man)p2;
instanceof关键字的使用
a instanceof A: 判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false
为了在强制类型转换时,不会出现异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。
Object
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类
- Object类只声明了一个空参的构造器。
==:运算符
- 可以使用在基本数据类型变量和引用数据类型变量中
- 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同,两个引用是否指向同一个对象实体。
equals()方法的使用:
- 是一个方法
- 只能适用于引用数据类型
- Object类中equals()的定义:
public boolean equals(Object obj){
return (this == obj);
}
说明Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否指向同一个对象。
- 像String、Date、File、包装类等都重写了equals的方法,重写以后,比较的是"实体内容"是否相同。
toString()的使用:
- 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
- Object 类中toString()的定义:
public String toString(){
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
包装类的使用
单元测试
步骤:
- 选中当前工程 - 右键选中:build path - add libraries - JUnit 4
- 创建Java类,进行单元测试
此时的Java类要求:①此类是public的②此类提供公共的无参的构造器 - 此类中声明单元测试方法。
此时的单元测试方法:方法的权限是public,没有返回值,没有形参 - 此单元测试方法上需要声明注释:@Test,并在单元测试类中导入:import org.junit.Test;
- 声明好单元测试方法以后,就可以在方法体内测试相关的代码。
- 写完代码以后,左键双击单元测试方法,右键:run as - Junit.Test;
包装类
// 包装类--->基本数据类型:调用包装类Xxx的xxxValue()
// 基本数据类型--->包装类:调用包装类的构造器
public void test() {
Integer in1 = 12;
int i1 = in1.intValue();
System.out.println(i1 + 1);
Float f1 = (float)12.3;
float f2 = f1.floatValue();
System.out.println(f2+1);
}
// String类型--->基本数据类型、包装类、调用包装类的parseXxx(String s)
public void test5() {
String str1 = "123";
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true1";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);
}
// 基本数据类型、包装类--->String类型:调用String重载的valueOf(Xxx xxx)
@Test
public void test4() {
int num1 = 10;
// 方式1:连接运算
String str1 = num1 + "";
// 方式2:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);
Double d1 = Double.valueOf(12.4f);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);
}
static
修饰属性:按是否使用static修饰,又分为:静态属性和非静态属性
实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。
静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过一个对象修改静态变量时,会导致其他对象调用此静态变量时, 是修改过了的。
① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用
② 静态变量的加载要早于对象的创建。
③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。
④
类变量 | 实例变量 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
修饰方法
①随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
②
静态方法 | 非静态方法 | |
---|---|---|
类 | yes | no |
对象 | yes | yes |
③ | ||
静态方法中,只可以调用静态的方法或属性 | ||
非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性 | ||
④在静态的方法中,不可以使用this或者super. |
单例设计模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
饿汉式
package practice;
import java.util.Scanner;
import java.util.Vector;
public class ScoreTest {
public static void main(String[] args) {
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
if (bank1 == bank2) {
System.out.println("相等");
}
}
}
// 饿汉式
class Bank{
// 1.私有化类的构造器
private Bank() {
}
// 2.内部创建类的对象
// 4.要求此对象也必须声明为静态的
private static Bank instance = new Bank();
// 3.提供公共的方法 返回类的对象
public static Bank getInstance() {
return instance;
}
}
懒汉式
package practice;
import java.util.Scanner;
import java.util.Vector;
public class ScoreTest {
public static void main(String[] args) {
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
if (bank1 == bank2) {
System.out.println("相等");
}
}
}
// 懒汉式
class Bank{
// 1.私有化类的构造器
private Bank() {
}
// 2.声明当前类对象,没有初始化
// 4.要求此对象也必须声明为静态的
private static Bank instance = null;
// 3.提供公共的方法 static的返回类的对象的方法
public static Bank getInstance() {
if (instance == null)
instance = new Bank();
return instance;
}
}
代码块
① 代码块的作用:初始化类、对象
②代码块如果有修饰的话,只能用static
③分类:静态代码块 vs 非静态代码块
④静态代码块
内部可以有输出语句
随着类的加载而执行,而且只执行一次
初始化类的信息
如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
静态代码块的执行要优先于非静态代码块的执行
⑤非静态代码块
内部可以有输出语句
随着对象的创建而执行
每创建一个对象,就执行一次非静态代码块
可以在创建对象时,对对象的属性等进行初始化
如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行。
final
① final:用来修饰一个类:此类不能被其他类所继承
② final:用来修饰一个方法:表明此方法不能被重写
③final:用来修饰一个变量:此时的“变量”就称为一个常量
> final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中赋值、构造器中
> final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。
抽象类
① abstract 修饰类:抽象类
> 此类不能实例化
② abstract 修饰方法
> 抽象方法只有方法的声明,没有方法体。
> 包含抽象方法的类一定是抽象类。反之抽象类不一定有抽象方法。
> 若子类重写了父类中的所有抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰。
③ 抽象类的匿名子类
// 需要重写所有的抽象方法
Person p = new Person(){
@Override
public void eat() {
System.out.println();
}
@Override
public void breath() {
System.out.println();
}
};
接口
接口的使用
- 接口使用interface来定义
- Java中,接口和类是并列的两个结构
- 如果定义接口:定义接口中的成员
3.1 JDK7及以前:只能定义全局变量和抽象方法
> 全局变量:public static final的书写时可以省略不写
> 抽象方法:public abstract的
3.2 JDK8:除了定义全局变量和抽象方法之外:还可以定义静态方法、默认方法 - 接口不能定义构造器!接口不可以实例化
- Java开发中,接口通过让类去实现(implements)的方式来使用。
如果实现类覆盖接口中的所有抽象方法,则此实现类就可以实例化。
如果实现类没有覆盖接口中所有的抽象方法,则实现类仍为一个抽象类。 - Java类可以实现多个接口 — > 弥补了Java单继承性的局限性
格式:class AA extends BB implements CC,DD,EE
- 接口与接口之间可以继承,而且可以多继承
- 接口的具体使用,体现多态性
- 接口,实际上可以看做是一种规范
JDK7
interface Flyable{
// 全局常量
public static final int MAX_SPEED = 7900; // 第一宇宙速度
int MIN_SPEED = 1; // 可以省略public static final
// 抽象方法
public abstract void fly();
void stop(); // 省略了public abstract
}
JDK8:除了定义全局变量和抽象方法之外:还可以定义静态方法、默认方法
接口中定义的静态方法,只能通过接口来调用
通过实现类的对象,可以调用接口中的默认方法
如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法。
如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,
那么子类在没有重写此方法的情况下,默认调用的是父类中同名同参数的方法。—>类优先原则
如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
那么在实现类没有重写的情况下,报错–>接口冲突
// 静态方法
public static void method1(){
System.out.println("CompareA:北京");
}
// 默认方法
public default void method2(){
System.out.println("CompareA:上海");
}
default void method3(){
System.out.println("");
}
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类。
Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
内部类的分类:成员内部类(静态、非静态) vs 局部内部类(方法内、代码块内、构造器内)
成员内部类:
一方面:作为外部类的成员;
>调用外部类的结构
>可以被static修饰
>可以被4中不同的权限修饰
另一方面,作为一个类
>类内可以定义属性,方法,构造器
>可以被final修饰,表示此类不能被继承。
>可以被abstract修饰
class Person{
String name;
int age;
public void eat(){
}
// 静态成员内部类
abstract static class Dog{
String name;
int age;
public void show(){
}
}
}