- 基本数据类型
- 基本数据类型是CPU可以直接进行运算的类型。Java定义了以下几种基本数据类型:
- 整数类型:byte,short,int,long
- 浮点数类型:float,double
- 字符类型:char
- 布尔类型:boolean
- char 类型可以保存中文
- 有多行字符串 """"""
- Java的字符串除了是一个引用类型外,还有个重要特点,就是字符串不可变.这个和C++不同
-
Java的数组有几个特点:
-
数组所有元素初始化为默认值,整型都是
0
,浮点型是0.0
,布尔型是false
; -
数组一旦创建后,大小就不可改变。
-
可以用
数组变量.length
获取数组大小
-
-
判断相等
- 要注意浮点数判断相等不能直接用
==
运算符; - 引用类型(字符串等)判断内容相等要使用
equals()
,注意避免NullPointerException
。
- 要注意浮点数判断相等不能直接用
-
switch 的 语法糖
->
不再需要 break -
for each 循环
public class Main {
public static void main(String[] args) {
int[] ns = { 1, 4, 9, 16, 25 };
for (int n : ns) {
System.out.println(n);
}
}
}
- 数组排序
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
Arrays.sort(ns);
System.out.println(Arrays.toString(ns));
}
}
-
二维数组
-
二维数组的每个数组元素的长度并不要求相同,例如,可以这么定义
ns
数组:int[][] ns = { { 1, 2, 3, 4 }, { 5, 6 }, { 7, 8, 9 } };
这个二维数组在内存中的结构如下:
┌───┬───┬───┬───┐ ┌───┐ ┌──▶│ 1 │ 2 │ 3 │ 4 │ ns ─────▶│░░░│──┘ └───┴───┴───┴───┘ ├───┤ ┌───┬───┐ │░░░│─────▶│ 5 │ 6 │ ├───┤ └───┴───┘ │░░░│──┐ ┌───┬───┬───┐ └───┘ └──▶│ 7 │ 8 │ 9 │ └───┴───┴───┘
-
打印二维数组 使用Java标准库的
Arrays.deepToString()
:
-
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[][] ns = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 }
};
System.out.println(Arrays.deepToString(ns));
}
}
-
命令行参数类型是
String[]
数组; -
Java标准库提供的核心类,包括:
- 字符串
- 包装类型
- JavaBean
- 枚举
- 常用工具类
-
Java语言本身提供的机制,包括:
- package
- classpath
- jar
-
一个Java源文件可以包含多个类的定义,但只能定义一个public类,且public类名必须与文件名一致。如果要定义多个public类,必须拆到多个Java源文件中。
-
在OOP中,
class
和instance
是“模版”和“实例”的关系;定义
class
就是定义了一种数据类型,对应的instance
是这种数据类型的实例;class
定义的field
,在每个instance
都会拥有各自的field
,且互不干扰;通过
new
操作符创建新的instance
,然后用变量指向它,即可通过变量来引用这个instance
;访问实例字段的方法是
变量名.字段名
;指向
instance
的变量都是引用变量。在JAVA中没有C++的
::
标识符!就算是类方法也用.
-
可变参数
-
可变参数用
类型...
定义,可变参数相当于数组类型: -
class Group { private String[] names; public void setNames(String... names) { this.names = names; } }
上面的
setNames()
就定义了一个可变参数。调用时,可以这么写:Group g = new Group(); g.setNames("Xiao Ming", "Xiao Hong", "Xiao Jun"); // 传入3个String g.setNames("Xiao Ming", "Xiao Hong"); // 传入2个String g.setNames("Xiao Ming"); // 传入1个String g.setNames(); // 传入0个String
-
C++ 中的可变参数可以用模板来做,也可以用 initial_list<> 来做
-
C 语言中的可变参数 printf 是专门有一个头文件来进行处理
-
-
基本类型参数的传递,是调用方值的复制。双方各自的后续修改,互不影响。这个和 python 如出一辙。
-
引用类型参数的传递,调用方的变量,和接收方的参数变量,指向的是同一个对象。双方任意一方对这个对象的修改,都会影响对方(因为指向同一个对象嘛)。这个和 python 如出一辙
-
构造方法的名称就是类名。构造方法的参数没有限制,在方法内部,也可以编写任意语句。但是,和普通方法相比,构造方法没有返回值(也没有
void
),调用构造方法,必须用new
操作符,这个就不如C++灵活。 -
没有在构造方法中初始化字段时,引用类型的字段默认是
null
,数值类型的字段用默认值,int
类型默认值是0
,布尔类型默认值是false
: -
在Java中,创建对象实例的时候,按照如下顺序进行初始化:
- 先初始化字段,例如,
int age = 10;
表示字段初始化为10
,double salary;
表示字段默认初始化为0
,String name;
表示引用类型字段默认初始化为null
; - 执行构造方法的代码进行初始化。
因此,构造方法的代码由于后运行,所以,
new Person("Xiao Ming", 12)
的字段值最终由构造方法的代码确定。 - 先初始化字段,例如,
-
可以定义多个构造方法,在通过
new
操作符调用的时候,编译器通过构造方法的参数数量、位置和类型自动区分: -
String
类提供了多个重载方法indexOf()
,可以查找子串:int indexOf(int ch)
:根据字符的Unicode码查找;int indexOf(String str)
:根据字符串查找;int indexOf(int ch, int fromIndex)
:根据字符查找,但指定起始位置;int indexOf(String str, int fromIndex)
根据字符串查找,但指定起始位置。
-
Java使用
extends
关键字来实现继承:注意:子类自动获得了父类的所有字段,严禁定义与父类重名的字段! -
继承树
-
注意到我们在定义
Person
的时候,没有写extends
。在Java中,没有明确写extends
的类,编译器会自动加上extends Object
。所以,任何类,除了Object
,都会继承自某个类。下图是Person
、Student
的继承树:┌───────────┐ │ Object │ └───────────┘ ▲ │ ┌───────────┐ │ Person │ └───────────┘ ▲ │ ┌───────────┐ │ Student │ └───────────┘
-
Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有
Object
特殊,它没有父类。类似的,如果我们定义一个继承自
Person
的Teacher
,它们的继承树关系如下:┌───────────┐ │ Object │ └───────────┘ ▲ │ ┌───────────┐ │ Person │ └───────────┘ ▲ ▲ │ │ │ │ ┌───────────┐ ┌───────────┐ │ Student │ │ Teacher │ └───────────┘ └───────────┘
-
-
用
protected
修饰的字段可以被子类访问:因此,protected
关键字可以把字段和方法的访问权限控制在继承树内部,一个protected
字段和方法可以被其子类,以及子类的子类所访问。 -
super
关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName
。 -
在Java中,任何
class
的构造方法,第一行语句必须是调用父类的构造方法。如果没有明确地调用父类的构造方法,编译器会帮我们自动加一句super();
,所以,Student
类的构造方法实际上是这样:class Student extends Person { protected int score; public Student(String name, int age, int score) { super(); // 自动调用父类的构造方法 this.score = score; } }
-
如果父类没有默认的构造方法,子类就必须显式调用
super()
并给出参数以便让编译器定位到父类的一个合适的构造方法。这里还顺带引出了另一个问题:即子类不会继承任何父类的构造方法。子类默认的构造方法是编译器自动生成的,不是继承的。
-
只要某个class没有
final
修饰符,那么任何类都可以从该class继承。 -
从Java 15开始,允许使用
sealed
修饰class,并通过permits
明确写出能够从该class继承的子类名称。例如,定义一个
Shape
类:public sealed class Shape permits Rect, Circle, Triangle { ... }
上述
Shape
类就是一个sealed
类,它只允许指定的3个类继承它。public final class Rect extends Shape {...}
是没问题的,因为
Rect
出现在Shape
的permits
列表中。 -
instanceof
实际上判断一个变量所指向的实例是否是指定类型,或者这个类型的子类。如果一个引用变量为null
,那么对任何instanceof
的判断都为false
。为了向下转型安全-
Person p = new Student(); if (p instanceof Student) { // 只有判断成功才会向下转型: Student s = (Student) p; // 一定会成功 }
-
-
Override和Overload不同的是,如果方法签名不同,就是Overload,Overload方法是一个新方法;如果方法签名相同,并且返回值也相同,就是
Override
。-
class Person { public void run() { … } } class Student extends Person { // 不是Override,因为参数不同: public void run(String s) { … } // 不是Override,因为返回值不同: public int run() { … } }
加上
@Override
可以让编译器帮助检查是否进行了正确的覆写。希望进行覆写,但是不小心写错了方法签名,编译器会报错。
-
-
多态的特性就是,运行期才能动态决定调用的子类方法。对某个类型调用某个方法,执行的实际方法可能是某个子类的覆写方法。
-
Object
定义了几个重要的方法:toString()
:把instance输出为String
;equals()
:判断两个instance是否逻辑相等;hashCode()
:计算一个instance的哈希值。
-
在子类的覆写方法中,如果要调用父类的被覆写的方法,可以通过
super
来调用-
class Person { protected String name; public String hello() { return "Hello, " + name; } } Student extends Person { @Override public String hello() { // 调用父类的hello()方法: return super.hello() + "!"; } }
-
-
继承可以允许子类覆写父类的方法。如果一个父类不允许子类对它的某个方法进行覆写,可以把该方法标记为
final
。用final
修饰的方法不能被Override
:而C++中是visual 关键字来说明是否可重写class Person { protected String name; public final String hello() { return "Hello, " + name; } } Student extends Person { // compile error: 不允许覆写 @Override public String hello() { } }
-
如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,目的是让子类去覆写它,那么,可以把父类的方法声明为抽象方法:也就是 C++ 中的纯虚方法
class Person { public abstract void run(); }
-
因为这个抽象方法本身是无法执行的,所以,
Person
类也无法被实例化。编译器会告诉我们,无法编译Person
类,因为它包含抽象方法。必须把
Person
类本身也声明为abstract
,才能正确编译它abstract class Person { public abstract void run(); }
-
抽象类:如果一个
class
定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract
修饰。因为无法执行抽象方法,因此这个类也必须申明为抽象类(abstract class)。
使用
abstract
修饰的类就是抽象类。我们无法实例化一个抽象类: -
接口:如果一个抽象类没有字段,所有方法全部都是抽象方法。
-
abstract class Person { public abstract void run(); public abstract String getName(); }
-
在Java中,使用
interface
可以声明一个接口:interface Person { void run(); String getName(); }
-
当一个具体的
class
去实现一个interface
时,需要使用implements
关键字。举个例子: -
class Student implements Person { private String name; public Student(String name) { this.name = name; } @Override public void run() { System.out.println(this.name + " run"); } @Override public String getName() { return this.name; } }
-
我们知道,在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个
interface
,例如:class Student implements Person, Hello { // 实现了两个interface ... }
-
-
接口继承:一个
interface
可以继承自另一个interface
。interface
继承自interface
使用extends
,它相当于扩展了接口的方法。-
interface Hello { void hello(); } interface Person extends Hello { void run(); String getName(); }
-
-
继承关系
-
合理设计
interface
和abstract class
的继承关系,可以充分复用代码。一般来说,公共逻辑适合放在abstract class
中,具体逻辑放到各个子类,而接口层次代表抽象程度。可以参考Java的集合类定义的一组接口、抽象类以及具体子类的继承关系:┌───────────────┐ │ Iterable │ └───────────────┘ ▲ ┌───────────────────┐ │ │ Object │ ┌───────────────┐ └───────────────────┘ │ Collection │ ▲ └───────────────┘ │ ▲ ▲ ┌───────────────────┐ │ └──────────│AbstractCollection │ ┌───────────────┐ └───────────────────┘ │ List │ ▲ └───────────────┘ │ ▲ ┌───────────────────┐ └──────────│ AbstractList │ └───────────────────┘ ▲ ▲ │ │ │ │ ┌────────────┐ ┌────────────┐ │ ArrayList │ │ LinkedList │ └────────────┘ └────────────┘
-
在使用的时候,实例化的对象永远只能是某个具体的子类,但总是通过接口去引用它,因为接口比抽象类更抽象:
List list = new ArrayList(); // 用List接口引用具体子类的实例 Collection coll = list; // 向上转型为Collection接口 Iterable it = coll; // 向上转型为Iterable接口
-
-
default 方法
-
在接口中,可以定义
default
方法。例如,把Person
接口的run()
方法改为default
方法: -
实现类可以不必覆写
default
方法。default
方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。如果新增的是default
方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。default
方法和抽象类的普通方法是有所不同的。因为interface
没有字段,default
方法无法访问字段,而抽象类的普通方法可以访问实例字段。但是可以通过内部函数调用来访问字段
-
-
接口的静态字段
-
因为
interface
是一个纯抽象类,所以它不能定义实例字段。但是,interface
是可以有静态字段的,并且静态字段必须为final
类型:. -
public interface Person { public static final int MALE = 1; public static final int FEMALE = 2; }
实际上,因为
interface
的字段只能是public static final
类型,所以我们可以把这些修饰符都去掉,上述代码可以简写为:public interface Person { // 编译器会自动加上public statc final: int MALE = 1; int FEMALE = 2; }
-
-
包作用域:位于同一个包的类,可以访问包作用域的字段和方法。不用
public
、protected
、private
修饰的字段和方法就是包作用域。例如,Person
类定义在hello
包下面:-
package hello; public class Person { // 包作用域: void hello() { System.out.println("Hello!"); } }
Main
类也定义在hello
包下面:package hello; public class Main { public static void main(String[] args) { Person p = new Person(); p.hello(); // 可以调用,因为Main和Person在同一个包 } }
-
-
import static 语法它可以导入可以导入一个类的静态字段和静态方法:很少使用。
-
package main; // 导入System类的所有静态字段和静态方法: import static java.lang.System.*; public class Main { public static void main(String[] args) { // 相当于调用System.out.println(…) out.println("Hello, world!"); } }
-
-
找包的流程
-
ava编译器最终编译出的
.class
文件只使用完整类名,因此,在代码中,当编译器遇到一个class
名称时:- 如果是完整类名,就直接根据完整类名查找这个
class
; - 如果是简单类名,按下面的顺序依次查找:
- 查找当前
package
是否存在这个class
; - 查找
import
的包是否包含这个class
; - 查找
java.lang
包是否包含这个class
。
- 查找当前
- 如果是完整类名,就直接根据完整类名查找这个
-
我们来看一个例子:
// Main.java package test; import java.text.Format; public class Main { public static void main(String[] args) { java.util.List list; // ok,使用完整类名 -> java.util.List Format format = null; // ok,使用import的类 -> java.text.Format String s = "hi"; // ok,使用java.lang包的String -> java.lang.String System.out.println(s); // ok,使用java.lang包的System -> java.lang.System MessageFormat mf = null; // 编译错误:无法找到MessageFormat: MessageFormat cannot be resolved to a type } }
因此,编写class的时候,编译器会自动帮我们做两个import动作:
- 默认自动
import
当前package
的其他class
; - 默认自动
import java.lang.*
。 - 注意:自动导入的是java.lang包,但类似java.lang.reflect这些包仍需要手动导入。
- 默认自动
-
-
public
- 定义为
public
的class
、interface
可以被其他任何类访问: - 定义为
public
的field
、method
可以被其他类访问,前提是首先有访问class
的权限:
- 定义为
-
private
- 定义为
private
的field
、method
无法被其他类访问: - 确切地说,
private
访问权限被限定在class
的内部,而且与方法声明顺序无关。推荐把private
方法放到后面,因为public
方法定义了类对外提供的功能,阅读代码的时候,应该先关注public
方法: - 由于Java支持嵌套类,如果一个类内部还定义了嵌套类,那么,嵌套类拥有访问
private
的权限:
- 定义为
-
protected
protected
作用于继承关系。定义为protected
的字段和方法可以被子类访问,以及子类的子类
-
package
-
最后,包作用域是指一个类允许访问同一个
package
的没有public
、private
修饰的class
,以及没有public
、protected
、private
修饰的字段和方法。 -
最后,包作用域是指一个类允许访问同一个
package
的没有public
、private
修饰的class
,以及没有public
、protected
、private
修饰的字段和方法。package abc; // package权限的类: class Hello { // package权限的方法: void hi() { } }
只要在同一个包,就可以访问
package
权限的class
、field
和method
:package abc; class Main { void foo() { // 可以访问package权限的类: Hello h = new Hello(); // 可以调用package权限的方法: h.hi(); } }
-
-
一个
.java
文件只能包含一个public
类,但可以包含多个非public
类。如果有public
类,文件名必须和public
类的名字相同。
标签:01,JAVA,String,子类,public,Person,方法,class,入门 From: https://www.cnblogs.com/mmxingye/p/16648464.html