二维数组
二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组。
数据类型[][] 数组名称 = new 数据类型 [行数][列数] { 初始化数据 };
例如:
public static void main(String[] args) { int[][] arr = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; //二维数组的每一行,相当于一维数组的每个元素 for(int row = 0; row < arr.length; row++) { for (int col = 0; col < arr[row].length; col++) { System.out.printf("%d\t", arr[row][col]); } System.out.println(""); } }
输出:
1 2 3 4
5 6 7 8
9 10 11 12
二维数组就类似于一个特殊的一维数组,每个元素相当于一个一维数组,每个一维数组的大小可以不同。
类和对象
什么是类?
类就是描述某个对象的一些属性和行为。
成员变量
成员变量定义在方法的外部,类的内部。
普通成员变量:
属于对象的,对象的引用与点号的结合进行访问,所占用的内存是在对象中的。
静态成员变量:
加static关键字,表面当前成员变量是属于类的变量。类变量是存放在方法区的。
成员方法
普通成员方法:属于对象的,对象的引用与点号的结合进行访问。
静态成员方法:不依赖于对象,直接可以通过类名点出来。
注意:不能在静态方法中使用非静态成员变量。(因为非静态成员变量依赖于对象
对象
通过描述,产生一个真正的实体对象,主要通过new关键字来实例化对象。
一个类可以实例化多个对象。
this 关键字
this是当前对象的引用,三种用法:
1.引用当前对象的变量:this.data
2.引用当前对象的方法:this.fun()
3.引用当前对象的构造方法:this()
构造方法
方法名与类名一样,没有返回值。
作用:实例化对象的时候调用,同时可以初始化我们的成员变量。
我们有两种初始化:
就地初始化:创建变量时赋值。
默认初始化:创建变量时不赋值。(变量是默认值,不同数据类型默认值是不同的)
当我们没有添加任何构造方法时,编译器会帮我们提供一个不带参数的构造方法,而当我们添加了构造方法时,编译器就不会再提供构造方法了。
注意:构造方法可以重载。
封装
含义:指将内部的实现细节进行了隐藏,不要让类外直接获取到我不想让它获取到的东西。从代码层面来讲,就是使用关键字private进行修饰。
我们可以使用get和set方法来对封装的数据进行访问。
代码块
普通代码块:定义在方法中的代码块。
构造代码块:定义在类中的代码块(加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。
静态代码块:使用static定义的代码块称为静态代码块。一般用于初始化静态成员变量。
new对象时,静态代码块和非静态代码块与构造方法的执行顺序:先是静态的执行(只执行一次,下次就不执行了),然后是非静态的,最后是构造方法执行。
内部类
即在类里再定义一个类。
非静态内部类
public class OutClass { private int a; static int b; int c; public void methodA() { a = 10; System.out.println(a); } public static void methodB() { System.out.println(b); } // 实例内部类:未被static修饰 class InnerClass { int c; public void methodInner() { // 在实例内部类中可以直接访问外部类中:任意访问限定符修饰的成员 a = 100; b = 200; methodA(); methodB(); // 如果外部类和实例内部类中具有相同名称成员时,优先访问的是内部类自己的 c = 300; System.out.println(c); // 如果要访问外部类同名成员时候,必须:外部类名称.this.同名成员名字 OutClass.this.c = 400; System.out.println(OutClass.this.c); } } public static void main(String[] args) { // 外部类:对象创建 以及 成员访问 OutClass outClass = new OutClass(); System.out.println(outClass.a); System.out.println(OutClass.b); System.out.println(outClass.c); outClass.methodA(); outClass.methodB(); System.out.println("=============实例内部类的访问============="); // 要访问实例内部类中成员,必须要创建实例内部类的对象 // 而普通内部类定义与外部类成员定义位置相同,因此创建实例内部类对象时必须借助外部类 // 创建实例内部类对象 OutClass.InnerClass innerClass1 = new OutClass().new InnerClass(); // 上述语法比较怪异,也可以先将外部类对象先创建出来,然后再创建实例内部类对象 OutClass.InnerClass innerClass2 = outClass.new InnerClass(); innerClass2.methodInner(); } }
注意:
- 外部类中的任何成员都可以在实例内部类方法中直接访问
- 实例内部类所处的位置与外部类成员位置相同,因此也受public、private等访问限定符的约束
- 在实例内部类方法中访问同名的成员时,优先访问自己的,如果要访问外部类同名的成员,必须:外部类名称.this.同名成员 来访问
- 实例内部类对象必须在先有外部类对象前提下才能创建
- 实例内部类的非静态方法中包含了一个指向外部类对象的引用
- 外部类中,不能直接访问实例内部类中的成员,如果要访问必须先要创建内部类的对象。
静态内部类
被static修饰的内部成员类称为静态内部类。
public class OutClass { private int a; static int b; public void methodA(){ a = 10; System.out.println(a); } public static void methodB(){ System.out.println(b); } // 静态内部类:被static修饰的成员内部类 static class InnerClass{ public void methodInner(){ // 在内部类中只能访问外部类的静态成员 // a = 100; // 编译失败,因为a不是静态变量 b =200; // methodA(); // 编译失败,因为methodB()不是静态成员方法 methodB(); } } public static void main(String[] args) { // 静态内部类对象创建 & 成员访问 OutClass.InnerClass innerClass = new OutClass.InnerClass(); innerClass.methodInner(); } }
注意:
- 在静态内部类中只能访问外部类中的静态成员
- 创建静态内部类对象时,不需要先创建外部类对象
总结:如果设计的内部类依赖于外部类对象,那就设计成非静态的内部类,反之就设计成静态内部类。
还有一个匿名内部类,就是没有名字的内部类,多用于接口的实现。
继承和多态
继承
class A extends B { }
为什么要继承呢?
继承是共性的抽取,从而达到对代码的复用。
子类继承父类的所有成员变量和方法(非静态的)。
super 关键字
该关键字主要作用:在子类方法中访问父类的成员。
super 的几种用法:
访问父类的成员变量:super.data
访问父类的方法:super.func()
调用父类的构造方法:super()
super 与 this 的区别
super和this都可以在成员方法中访问:成员变量和调用其他的成员函数,都可以作为构造方法的第一条语句,那它们之间有什么区别呢?
同:
- 都是Java中的关键字
- 只能在类的非静态方法中使用,用来访问非静态成员方法和字段
- 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
异:
- this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成员的引用
- 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性
- 在构造方法中:this(…)用于调用本类构造方法,super(…)用于调用父类构造方法,两种调用不能同时在构造 方法中出现
- 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有
代码块执行顺序
class Person { public String name; public int age; public Person(String name, int age) { this.name = name; this.age = age; System.out.println("Person:构造方法执行"); } { System.out.println("Person:实例代码块执行"); } static { System.out.println("Person:静态代码块执行"); } } class Student extends Person{ public Student(String name,int age) { super(name,age); System.out.println("Student:构造方法执行"); } { System.out.println("Student:实例代码块执行"); } static { System.out.println("Student:静态代码块执行"); } } public class TestDemo4 { public static void main(String[] args) { Student student1 = new Student("张三", 15); System.out.println("==========================="); Student student2 = new Student("李四", 35); } }
输出:
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
访问修饰限定符
final 关键字
final关键可以用来修饰变量、成员方法以及类。
注意三个点:
- 修饰变量或字段,表示常量(即不能修改)
- 修饰类:表示此类不能被继承
- 修饰方法:表示该方法不能被重写
多态
啥是多态?
就是一个引用,引用的对象不一样, 所表现的行为不一样, 这种思想被称为多态.
向上转型
class Animal { } class Cat extends Animal { }
父类类型引用子类对象, 这便是向上转型.
Animal animal = new Cat();
缺点 : 只能通过父类引用 访问父类自己的成员.
什么时候发生向上转型呢?
第一种就是直接赋值了 :
Animal animal = new Cat();
还有就是方法的传参 , 就是将子类对象传入父类类型参数里 :
public static void fun(Animal animal) { //这里传入Cat类型参数,就是向上转型了 }
再就是方法的返回值了 :
public static Animal fun(Animal animal) { return new Cat(); }
关于动态绑定 : 通过父类引用 , 调用子类重写了的父类的方法.