面向对象
Pascal语言的设计者如是说:“算法 + 数据结构 = 程序”。传统的结构化程序设计算法是第一位的,数据结构是第二位的。而面向对象程序设计则把数据放在了第一位,然后再考虑操作数据的算法。对于面向对象程序设计,在较高的层面上,对象是根据某个类创建出来的一个实例,表示某类事物中一个具体的个体。对象具有各种属性,并且具有一些特定的行为。而在较低的层面上,站在计算机的角度,对象就是内存中的一个内存块,在这个内存块封装了一些数据,也就是类中定义的各个属性,所以,对象是用来封装数据的。
类的定义
public class ClassName{
field1;
field2;
...
constructor1;
constructor2;
...
method1;
method2;
...
}
注意:
-
Java的源文件名必须和public类的类名保持一致,因此一个Java源文件只能有一个public类。
-
对于有多个类的源文件,编译器会在指定的目录下为每个类生成字节码文件。
-
如果把每个类单独放在一个源文件里面,可以在使用javac进行编译的时候使用通配符*,这样所有与通配符匹配的类都会被编译。当没有显示编译一个类时,若这个类包含在一个被编译的类里面,编译器会自动搜索有没有这个类的字节码文件。若没有,则对它进行编译;若有,且如果已有的源文件较已有的字节码文件有更新,编译器会自动重新编译这个类。
访问修饰符
访问修饰符包括三种:
访问级别 public > protected > default > private
* public 所有包中的类都可以调用或者访问
* protected 只允许它的子类或者在同一个包中的类调用或者访问。
* default(默认的,没有关键字) 只有同一个包中的类允许调用或者访问。
* private 只能在同一个类里面调用或者访问。
字段
实例字段
对象中的数据就是实例字段,或者叫做对象成员变量。
public class ClassName{
访问修饰符 数据类型 字段名;
}
实例字段的初始化:
-
默认初始化:字段与局部变量一个最重要的区别就是方法中的局部变量必须明确地初始化。而在类中,如果没有初始化类中的字段,将会自动初始化为默认值(0、false、null)。
-
显式初始化:程序员手动给实例字段赋值,在执行构造方法之前先执行这个赋值操作。
-
通过构造方法进行初始化。
-
通过初始化块进行初始化。
类字段
类中的数据就是类字段,或者叫做类成员变量。类字段独立于每个对象,在对象未创建的时候就存在,可以直接使用类名调用。
public class ClassName{
访问修饰符 static 数据类型 字段名;
}
类字段的初始化:
类字段的初始化基本上和实例字段的初始化一样,只不过类字段可以在静态代码块中初始化,而实例字段则不可以。
final实例字段
public class ClassName{
访问修饰符 final 数据类型 字段名;
}
final实例字段的初始化:
final实例字段和普通的实例字段的初始化没有什么不同,只不过一旦初始化,以后就不能再修改这个字段了。初始化时一定要小心。
final类字段
public class ClassName{
访问修饰符 final 数据类型 字段名;
访问修饰符 final static 数据类型 字段名;
}
final类字段的初始化:
final类字段的初始化和final实例字段的情况相同,只不过它也能在静态代码块中进行初始化,一旦初始化,就不能再修改这个字段了。初始化时一定要小心。
方法
方法的返回值
- 方法的返回值可以是基本类型的数据,也可以是引用类型的数据。如果没有返回值,则返回值类型使用void关键字。
- 给方法的调用者返回数据使用return关键字。执行return语句会结束并跳出方法。
方法的参数
按值调用(call by value)
方法接收的是调用者提供的值。
按引用调用(call by reference)
方法接收的是调用者提供的变量地址。
Java总是采用按值调用,因此一个方法不可能修改传入的基本类型的变量。对于引用类型的变量,由于形参和实参指向的都是同一个对象,因此可以修改引用变量指向的对象的数据,但不能修改引用变量的值。
隐式的参数(this)
每个方法都隐式地包含了一个指向当前调用对象的this变量作为参数。
可变参数
当传入的参数有多个同类型的数据时,可以使用可变参数。
//第一种方式:数据类型[] 变量名,如main方法里面的参数。
public static void main(String[] args) {
}
//第二种方式:数据类型... 变量名;
public void func(int... params){
}
注意:
可变参数只能在所有参数的最后面
方法的重载
对于同一个类中的多个方法,有相同的名字,不同的参数,便出现了方法的重载。编译器根据方法的签名(参数的数据类型,个数,和顺序)来选择调用哪个具体的方法,返回值类型不是签名的一部分。任何方法都可以重载。
实例方法
[访问权限修饰符] 返回值类型 方法名(参数列表){
方法体;
}
注意:
- 实例方法也可以叫做对象成员方法。
- 实例方法可以操作实例字段也可以操作类字段,可以调用的实例方法,也可以调用类方法。
- 实例方法的调用必须依赖于对象
类方法
[访问权限修饰符] static 返回值类型 方法名(参数列表){
方法体;
}
注意:
- 类方法也可以叫做类成员变量。
- 类方法独立于每个对象,在对象未创建的时候就存在,可以直接使用类名调用。
- 类方法不能使用实例变量,也不能调用实例方法。
main方法
main方法的类会自动进行加载,每一个类都可以由一个mian方法,但不一定会执行。想要独立地测试某一个类,可以使用 java 执行该类,该类的main方法就会自动开始执行,这是常用的对类进行单元测试的一个技巧。
构造方法
- 构造方法的方法名必须和类名一致。
- 构造方法没有返回值,不需要加返回值类型。
- 没有参数的构造方法叫无参构造方法。没有构造方法时,编译器会自动添加无参构造方法;有其他的构造方法时不会添加,程序员需要手动添加无参构造。
- 在idea中可以使用alt + insert自动生成构造方法。
final修饰的方法
final修饰的方法不能够被子类重写。
继承
class A{
}
//使用extends关键字
class B extends A{
}
说明:
java只支持单继承。
所有类都直接或者间接继承了Object类,如果没有extends关
键字,默认添加extends Object。
继承的类叫子类或者派生类,被继承的类叫做父类或者基类。
子类会继承父类所有非私有的属性和方法。
protected的作用是对本包下的所有类和其他包下的子类可见。
final修饰的类不能被继承。
super和this
-
this是当前对象的引用,即当前对象是谁,就指向谁。
super是父类对象的引用。
-
this访问本类的属性和方法,如果本类没有,则访问父类的属性和发方法。
super访问父类的属性和方法,如果本类没有,则访问父类的属性和方法。
-
this可以调用本类对象的构造方法,必须放在首行。
super可以调用父类的构造方法,必须放在首行。
因此二者不可以同时使用于一个构造方法里面。
类型转换
-
父类引用指向子类对象,叫向上转型,不需要强制进行。当向上转型之后,父类引用变量可以访问子类中属于父类的属性和方法,但是不能访问子类独有的属性和方法。
-
子类引用指向父类对象,叫向下转型,需要强制转换,而且必须有继承关系。
较高级别的基本数据类型转换为较低级别的基本数据类型属于强制类型转换,较低级别的基本数据类型转换为极高级别的基本数据类型属于自动类型转换
instance of关键字
X instance of Y
说明:
instanceof是Java的一个关键字,左边是对象,右边是类,返回值是Boolean类型。
它的具体作用是测试左边的对象是否是由右边的类或者该类的子类创建的实例对象.若是,则返回true,否则返回false。
X和Y必须具有继承关系,否则编译阶段就会报错。
public class Test02 {
public static void main(String[] args) {
Student student = new Student();
Person person = new Person();
System.out.println(student instanceof Student); //true,student是Student类的一个实例
System.out.println(student instanceof Person); //true,student是Person的子类Student的一个实例,因此也是Person类的一个实例
System.out.println(person instanceof Student); //false,person是Student的父类Person的一个实例,可以这么理解,不是所有的人都是学生。
person = student;
System.out.println(person instanceof Student); //true,将student向上转型为Person类的一个实例后,可以这么理解,已经限定了这个人就是学生。
}
}
class Person{}
class Student extends Person{}
抽象类
-
//抽象类的定义方式 abstract class A{ //抽象方法 public abstract void func(); ... } 说明: 1.abstract和final不可以同用,因为abstract修 饰的方法需要被实现,而final修饰的方法不允许实现,二者相悖。 2.abstract和static不可以同用,因为静态方法的覆盖是没有多 态的,所以abstaract和static配合是没有意义的,子类再怎么重 写,他都是调父类的静态方法。 3.private和abstract不能搭配,因为不能继承private。 5.private、static、final 都不能和abstract用,他们之 间可以随便混合着用。
-
抽象类不能实例化。
-
只要还有一个抽象方法,这个类就是抽象类。
-
抽象类可以完全重写或覆盖接口中的方法,也可只重写接口中的部分方法。
-
抽象类可以继承实体类,但前提是实体类必须有明确的构造函数。
接口
//接口的定义
interface A{
void func1();
int func2();
...
}
//实现类
class B implements A,...{
@override
void func1(){
...
}
int func2(){
...
}
}
说明:
类只有单继承,但可以有多实现。
实现类必须实现接口的所有方法。
接口中的方法默认都是public abstract。
接口中只能定义常量,默认为public static final。
接口不能被实例化.
接口可以继承多个接口
内部类
1. 普通内部类
//内部类的定义
class Outer{
private int i;
Outer(int i){
this.i = i;
}
class Inner{
void printI(){
System.out.println(i);
}
}
}
//内部类对象的创建
public class Test{
public static void main(String args[]){
Outer outer = new Outer(2);
Outer.Inner inner = outer.new Inner();
inner.printI(); //2
}
}
说明:
内部类的创建需要依赖于外部类,在创建一个内部类的时候需要先创 建外部类。
内部类可以访问外部类所有权限的属性。
2. 静态内部类
//静态内部类的定义
class Outer{
private static int i =0;
static class Inner{
void printI(){
System.out.println(i);
}
}
}
//静态内部类对象的创建
public class Test{
public static void main(String args[]){
Outer.Inner inner = new Outer.Inner(); //注意与普通内部类的不同
inner.printI(); //0
}
}
说明:
静态内部类也是作为一个外部类的静态成员而存在。
静态内部类和静态方法一样只能访问静态成员。
静态内部类对象的创建方式与普通内部类对象的创建方式有所不同。
3. 匿名内部类
- 没有名字初始化类,不将实例的引用保存到变量中。
- 匿名内部类可以实现接口,重写接口里面的所有方法。
- 匿名内部类可以继承抽象类,重写里面的抽象方法。
- lambda表达式,减少实现或继承的代码。
4. 局部内部类
- 在方法内部定义的类。
- 可以访问外部类的成员变量,静态方法内定义的内部类只能访问静态成员变量。