1. 类和对象
1.1 定义
- 三种最常见的成员:构造器、成员变量和方法
定义类:
修饰符:public
、protected
、private
三个最多只能出现1个;它们可以与static
、final
组合起来修饰方法
定义成员变量:
修饰符:public
、final
、abstract
三个最多只能出现1个
定义方法:
修饰符:public
、protected
、private
三个最多只能出现1个;final
、abstract
最多最多只能出现其一,它们可以与static
组合起来修饰方法
返回值:可以是Java语言允许的任何数据类型
方法名:方法名的命名规则与成员变量的命名规则相同
形参列表:用于定义该方法可以接受的参数
定义构造器:
修饰符:public
、protected
、private
三个最多只能出现1个
构造器名:必须和类名相同
形参列表:用于定义该方法可以接受的参数
1.2 this引用
使用this有两种情形:
- 构造器中引用该构造器正在初始化的对象
- 在方法中引用调用该方法的对象
- 它所代表的对象是不确定的,但它的类型是确定的
静态成员不能直接访问非静态成员,因为
static
修饰的方法中不能使用this
2. 方法详解
2.1 方法参数传递
- 方法只能通过值传递来传递参数,即将实际参数的副本传入方法内,而参数本身不会受到影响
- 引用变量通过栈内存指向堆内存进行分配,非引用变量只在栈内存进行分配
2.2 形参个数可变的方法
- 本质就是一个数组参数
- 一个方法最多只能有一个个数可变参数
public static void test(int a, String...books){
for(String book : books){
System.out.println(book);
}
}
2.3 递归方法
public class Recursive {
public static int febonaci(int n){
if(n == 1){
return 1;
}
if(n == 2){
return 2;
}
else{
return febonaci( n -1) + febonaci(n - 2);
}
}
public static void main(String[] args){
System.out.println(febonaci(8));
}
}
2.4 方法重载
- Java允许同一个类里定义多个同名方法,只要形参列表不同就行
3. 成员变量和局部变量
3.1 变量分类
变量分类图- 同名局部变量会覆盖成员变量,如果这个是后需要引用被覆盖的成员变量,则可使用this或类名来作为调用者
3.2 成员变量的初始化过程
-
成员变量系统会自动进行初始化过程
成员变量初始化示意图 - eyeNum属于Person类,name属于对象
3.3局部变量的初始化过程
- 局部变量定义后,必须进行显式初始化才能使用,系统不会为局部变量执行初始化
3.4 变量的使用规则
成员变量适用情形:
- 描述类的固有信息
- 某个类中需要以一个变量来保存该类或者实例运行时的状态信息
- 需要在某个类或者多个方法之间进行共享的信息
4. 隐藏和封装
4.1 封装
- 将对象的状态信息隐藏在对象内部,不允许外部程序直接访问
4.2 使用访问控制符
private
:当前类访问权限
default
:包访问权限
protected
:子类访问权限
public
:公共访问权限
- 类里绝大部分成员变量都应该使用
private
修饰,只有一些static修饰的成员变量才可考虑用public
- 如果一个类主要用作其他的父类,则主要使用
protected
- 希望暴露出来的用
public
4.3 package、import和import static
- 同一个包中的类不必位于相同的目录下,源文件里通过
package
语句来指定包名,class
文件必须放在对应的路径下 - 包名应该全部是小写字母,由单词连缀
- 同一个包下的类可以互相访问,不处于同一个类则需要使用类的全名来访问
-
import
导入包下的类,import static
导入类中特定的静态成员变量、方法
5. 构造器详解
5.1 使用构造器执行初始化
- 当使用构造器时,系统先会为该对象分配内存空间,并为这个对象进行默认初始化。这个对象还不能被外部所访问,只能在该构造器中通过this来引用
5.2 构造器重载
- 让程序更简洁,降低软件的维护成本
public class Orange {
private int price;
private String orangeName;
public Orange(int price){
this.price = price;
}
public Orange(int price, String orangeName){
this(price);
this.orangeName = orangeName;
}
}
5.6 类的继承
5.6.1 继承基础
- 每个类最多只有一个直接父类,否则编译错误
- 调用父类方法和变量
public class Fruit {
public double weight;
public void info(){
System.out.println("My weight is"+this.weight);
}
}
public class Orange extends Fruit{
private int price;
private String orangeName;
public Orange(int price){
this.price = price;
}
public Orange(int price, String orangeName){
this(price);
this.orangeName = orangeName;
}
public static void main(String[] args){
Orange orange = new Orange(1, "Orange1");
System.out.println(orange.weight); //0.0
System.out.println(orange.price); //1
System.out.println(orange.orangeName); //Orange1
orange.info(); //My weight is0.0
}
}
5.6.2 重写父类方法
- 重写后,子类执行重写后的方法,若需要使用父类方法,可使用
super
或者父类类名 -
private
方法不能重写
@Override
public void info() {
super.info();
System.out.println("Now I have extended the original class");
}
5.6.3 super
- 不能出现在
static
修饰的方法内 - 限定访问该实例的父类的变量、方法
如果在某个方法中访问名为a
的成员变量,但没有指定调用者,则系统查找a的顺序为:
- 查找该类方法中是否有名为
a
的局部变量 - 查找该类中是否有名为
a
的成员变量 - 查找该类的父类是否有包含
a
的成员变量,直至Object
类
5.6.4 调用父类构造器
- 使用super来调用
- 不管是否使用super来显式调用父类构造器,子类构造器总会调用父类构造器一次
public class Fruit {
public double weight;
public Fruit(){
System.out.println("这是一个无参构造器");
}
public Fruit(double weight){
this.weight = weight;
}
public void info(){
System.out.println("My weight is"+this.weight);
}
}
public class Orange extends Fruit{
private int price;
private String orangeName;
public Orange(int price){
this.price = price;
System.out.println("Orange构造器,带price");
}
public Orange(int price, String orangeName){
this(price);
this.orangeName = orangeName;
System.out.println("Orange构造器,带price和name");
}
public static void main(String[] args){
Orange orange = new Orange(1, "Orange1");
}
}
结果
父类指定了有参构造函数时,子类必须要重写父类的构造函数;父类只有无参构造函数时,子类无需重写
5.7 多态
5.7.1 多态性
Java引用变量有两个类型,一个是编译时类型,一个是运行时类型,如果编译类型和运行类型不一致,就可能出现所谓的多态
- 向上转型:子类赋值给父类,当运行该变量时,总是体现出子类的特征;但是方法都是父类的方法,变量还是子类的变量
-
向下转型:父类变量通过显式语句转化为子类变量,转化情形:
1. 基本类型:只能在数值类型之间进行
2.引用类型:只能在具有继承关系的两个类型之间进行。如果一个父类实例转换为子类对象,则这个对象必须实际上是子类实例才行(执行时为子类对象) -
instanceof:判断A所属类型是否是B的实例
5.8 继承与组合
- 继承表达”是“的关系,组合表达”有“的关系
5.9 初始化块
5.9.1 初始化块基本用法
- 与构造器功能类似
- 当创建Java对象时,系统总会先调用该类里定义的初始化块,如果一个类里定义了2个普通初始化块,则前面定义的初始化块先执行,后面定义的初始化块后执行
5.9.2 静态初始化块
- 静态初始化块属于类的静态成员,也遵守静态成员不能访问非静态成员的规则
5.9.3 初始化块和构造器
- 初始化块在构造器之前执行
public class Fruit {
static{
System.out.println("Fruit的静态初始化块");
}
public double weight;
{
System.out.println("这是Fruit的初始化块");
}
public Fruit(){
System.out.println("这是一个无参构造器");
}
public Fruit(double weight){
this.weight = weight;
}
public void info(){
System.out.println("My weight is"+this.weight);
}
}
public class Orange extends Fruit{
private int price;
private String orangeName;
static{
System.out.println("orange的静态初始化块");
}
{
System.out.println("这是Orange的初始化块");
}
public double weight = 3.0;
public Orange(){
System.out.println("orange无参");
}
public Orange(int price){
this.price = price;
System.out.println("Orange构造器,带price");
}
public Orange(int price, String orangeName){
this.orangeName = orangeName;
System.out.println("Orange构造器,带price和name");
}
@Override
public void info() {
super.info();
System.out.println("Now I have extended the original class");
}
public static void main(String[] args){
Orange orange = new Orange(1, "Orange1");
}
}
初始化块和构造器
6. 处理对象
6.1 打印对象和toString方法
@Override
public String toString() {
return "the price of orange is" + this.price;
}
toString重写
6.2 ==和equals方法
==:两个变量是否指向同一个堆内存空间
equals:Object提供的方法
- 对于引用变量,如果equals没重写,二者没什么区别,都需要指向同一个对象才返回
true
- 对于基本类型,==判断二者值是否相等,equals不能用在基本类型
String s1 = new String("123");
String s2 = new String("123");
String s3 = "123";
String s4 = "123";
System.out.println(s1==s2); // false
System.out.println(s3==s4); // true
new
创建出来的变量s1
和s2
保存在堆内存中,所以二者==
会输出false
。他们在创建的时候都首先保存在常量池再保存在堆内存
7. 类成员
7.1 理解类成员
- 类成员不能访问实例成员
7.2 单例类
- 一个只允许创建一个对象的类
public class singleInstance {
private static singleInstance singleIns;
public static singleInstance getInstance(){
if (singleIns == null){
singleIns = new singleInstance();
}
return singleIns;
}
public static void main(String[] args){
singleInstance s1 = singleInstance.getInstance();
singleInstance s2 = singleInstance.getInstance();
System.out.println(s1 == s2);
}
}
7.3 final修饰符
- 表示它修饰的类、方法和变量不可变
7.3.1 final成员变量
- final修饰的成员变量必须显式指定其初始值
- 实例final变量只能在构造器,初始化块和声明三个地方初始化
- 静态final变量只能在声明和初始化块两个地方初始化
7.3.2 final局部变量
- 只能在通过声明初始化
7.3.3 final修饰基本类型和引用类型
- final只能保证引用变量的地址不变
final int[] a = new int[]{1,2,3};
a[0] = 2;
System.out.println(Arrays.toString(a)); //[2,2,3]
7.3.4 final方法
- 不可被重写
7.3.5 final类
- 不可以有子类
7.3.6 不可变类
- 创建该类的实例后,该实例的实例变量是不可变的
- Java的8个包装类和String类都是不可变类
7.4 抽象类
7.4.1 抽象方法和抽象类
- 用
abstract
修饰,不能有方法体 - 抽象类不能被实例化
- 抽象类可以包含成员变量,方法,构造器,初始化块,内部类5中成分,但构造器不能用来创建实例
- 含有抽象方法的类只能被定义成抽象类
- 继承抽象类必须实现抽象类的所有抽象方法
-
final
和abstract
不能一起使用;static
和abstract
不能同时修饰某一个方法
7.5 接口
-
interface
定义 - 一个接口可以有多个直接父类接口,但接口只能继承接口,不能继承类
- 接口可以包含成员变量(静态常量
public static final
)、方法(抽象实例方法、类方法、默认方法或私有方法public abstract
),内部类(public static
) -
默认方法必须使用default修饰,不能使用static,系统回味默认方法自动添加
public
修饰符 默认方法:就是实例方法,不需要实现类去实现其方法
public static void main(String[] args){
Orange orange = new Orange(1, "Orange1");
orange.goodForHealth();
}
public interface healthyable {
public default void goodForHealth() {
System.out.println("健康增加");
}
}
-
static
方法不能用default
方法修饰,类方法也总是由public
修饰
7.5.1 接口的继承
- 一个接口可以有多个直接父接口
- 使用
extends
继承接口
7.5.2 接口的使用
- 一个类可以继承多个接口
- 接口不能显式继承任何类,但所有接口类型的引用变量都可以直接赋值给Object类型的引用变量,利用向上转型来完成
7.5.3 接口和抽象类
- 接口里不包含构造器,抽象类里可以包含构造器
- 接口里不能包含初始化块,但抽象类里有
- 方法
- 变量
- 继承
7.5.4 面向接口编程
1. 简单工厂模式
工厂模式-
computer
从OutputFactory
获取Output
对象,并进行使用 -
OutputFactory
通过实现Printer
类来返回output
对象
2.命令模式
-
适用情况:某个方法需要完成某一个行为,但这个行为的具体实现无法确定,必须等到执行该方法才可以确定
命令模式
8. 内部类
- 内部类提供了更好的封装,不允许同一个包中的其他类访问该类
- 内部类成员可以直接访问外部类的私有数据
- 匿名内部类适合用于创建那些仅需要一次使用的类
8.1 非静态内部类
- 内部类比外部类可以多使用三个修饰符:private,protected,static
- 非静态内部类不能拥有静态成员
- 非静态内部类成员可以访问外部类private成员,但反过来不成立,即外部类不能访问非静态内部类private成员
- 如果存在一个非静态内部类对象,则一定存在一个外部类对象,但外部类对象里不一定寄生了非静态内部类对象
8.2 静态内部类
- 静态内部类可以包含静态成员和非静态成员
- 静态内部类不能访问外部类的实例成员
- Java允许在接口里定义内部类,默认使用public static修饰
8.3 使用内部类
下面分3中情况讨论内部类的用法
1. 在外部类内部使用内部类
定义和使用都没有太大的区别
2. 在外部类以外使用非静态内部类
- 内部类不能使用
private
修饰 - 定义内部类的语法为
OuterClass.InnerClass varName
class OutClass {
class In{
public In(String msg){
System.out.println(msg);
}
}
}
class Out extends OutClass.In{
public Out(OutClass outClass){
outClass.super("hello"); //注意这里的用法,通过outclass调用In的构造函数
}
public static void main(String[] args){
OutClass.In in = new OutClass().new In("has been created");
Out out = new Out(new OutClass());
}
}
3. 在外部类以外使用静态内部类
StaticOut.StaticIn in = new StaticOut.StaticIn()
- 内部类不可以被子类重写
8.4 局部内部类
- 生成的class文件遵循
OuterClass$NInnerClass
命名规则 - 用法比较鸡肋,很少使用
8.5 匿名内部类
- 适合于创建那种只需要一次使用的类
- 创建匿名类时会立即创建一个该类的实例,这个类定义就消失
- 匿名内部类不能是抽象类,因为在创建匿名内部类的时候,会立即创建匿名内部类对象
- 匿名内部类不能定义构造器,因为匿名内部类没有类名
实现Interface
public class man {
String msg = "123";
public man(Runnable runnable){
runnable.RunStart();
runnable.RunFinish(this.msg);
}
public static void main(String[] args){
man m1 = new man(new Runnable() {
@Override
public void RunStart() {
}
@Override
public void RunFinish(String msg) {
}
});
}
}
实现子类
public static void main(String[] args){
Orange orange = new Orange(1, "Orange1"){
@Override
public String toString() {
return super.toString();
}
};
}
- 内部类访问的外部类变量必须用
final
修饰
为什么内部类调用的外部变量必须是final修饰的?
9. Lambda表达式
三部分组成:
1)形参列表
2)箭头
3)代码块
public interface Runnable {
public void RunStart();
}
public class man {
String msg = "123";
public man(Runnable runnable){
runnable.RunStart();
}
public static void main(String[] args){
man m1 = new man(() ->{
System.out.println("123");
});
}
}
- Lambda的目标类型必须是“函数式接口”
- 如果带有
@FunctionalInterface
, 则可以实行强制类型转换
9.1 方法引用与构造引用
1. 引用类方法
public class man {
String msg = "123";
public man(Runnable runnable){
}
public static void main(String[] args){
Runnable runnable = Integer::valueOf;
Integer val = runnable.RunStart("123");
System.out.println(val);
}
}
- 当调用
Converter
接口中的唯一的抽象方法时,调用参数将回传给Integer
类的valueOf()
2. 引用特定对象的实例方法
public int info(String s) {
System.out.println(s);
return s.length();
}
Orange orange = new Orange(1);
Runnable runnable = orange::info;
3. 引用某类对象的实例方法
MyTest mt = String::substring;
4. 引用构造器
YourTest yt = JFrame:: new
9.2 Lambda表岛是与匿名类的联系
-lambda
表达式是匿名内部类的一种简化
10. 枚举类
10.1 枚举类入门
- 枚举类可以实现一个或多个接口,不能显式继承其他父类。
-
java.lang.Enum
类实现了Serializable
和Comparable
两个接口 - 默认使用
final
修饰,因此枚举类不能派生子类 - 只能用
private
修饰,如果省略了构造器的访问控制符,则默认使用private
- 枚举类所有实例在第一行显示列出
public enum SeasonNum {
SPRING,SUMMER,FALL,WINTER;
}
public class EnumTest {
public static void judge(SeasonNum s){
switch (s) {
case SPRING:
System.out.println("SPring");
break;
case SUMMER:
System.out.println("SUmmer");
break;
default:
System.out.println("have no idea");
}
}
public static void main(String[] args){
for(SeasonNum s: SeasonNum.values()){
judge(s);
}
}
}
java.lang.Enum的方法:
-
int compareTo
:用于与指定枚举对象比较顺序 -
String name()
:返回此枚举类实例的名称 -
int ordinal
:返回枚举值在枚举类中的索引值 -
String toString()
:返回枚举常量的名称 -
valuieOf()
:枚举类中指定名称的枚举值 -
values()
:所有枚举名称
10.2 枚举类的成员变量、方法和构造器
public class EnumTest {
public static void judge(SeasonNum s){
switch (s) {
case SPRING:
System.out.println("SPring");
break;
case SUMMER:
System.out.println("SUmmer");
break;
default:
System.out.println("have no idea");
}
}
public static void main(String[] args){
SeasonNum s = Enum.valueOf(SeasonNum.class, "SPRING");
s.seansonName = "春天";
System.out.println(s + s.seansonName);
}
}
构造器
public enum SeasonNum {
SPRING("春天"),SUMMER("夏天"),FALL("qiutian"),WINTER("dongtian");
private final String name;
private SeasonNum(String seansonName){
this.name = seansonName;
}
public String seansonName;
}
网友评论