一般函数:对象创建后,需要函数功能时才调用。 对象创建后,可以被调用多次。有返回值
//构造函数重载
class Person {
private String name;
private int age;
public Person() {//空参数构造函数
}
Person(String n, int a) {//带有两个参数的构造函数
name = n;
age = a;
}
public String talk() {
return "我是: " + name + ",今年: " + age + "岁 ";
}
}
public class Construct {
public static void main(String[] args) {
Person p = new Person();//调用空参数构造函数
System.out.println(p.talk());//打印姓名和年龄
Person p1 = new Person("小明",20);//调用有参数构造函数并传入参数
System.out.println(p1.talk());//打印姓名和年龄
}
}
输出结果为:
我是: null,今年: 0岁我是: 小明,今年: 20岁由结果可以看出:构造函数中String类型默认初始化值为null,int类型默认初始化值为0。
4、this关键字
class Person {
String name;
int age;
public Person() {
System.out.println("1. public Person()");
}
public Person(String name, int age) {
this();// 调用本类中无参构造方法,即Person(){},必须定义在构造函数的第一行
this.name = name;//this表示当前对象
this.age = age;//this表示当前对象
System.out.println("2. public Person(String name,int age)");
}
}
public class TestThis {
public static void main(String[] args) {
new Person("小明", 20);
}
}
输出结果为:
1. public Person()
2. public Person(String name,int age)
由此可见,this关键字可以表示当前对象,也可以在构造函数中调用另一个构造函数。
5、static关键字
class Person {
String name;
private static String city = "北京";// 静态变量被所有对象共享
int age;
public Person() {
System.out.println("1.public Person()");
}
// 此段代码会首先被执行——静态代码块
static {
System.out.println("2.Person 类的静态代码块被调用! ");
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String talk() {
return "我是:" + this.name + ",今年:" + this.age + "岁,来自:" + city;
}
// 静态方法定义的内容可以用于非静态和静态方法中使用
// 静态方法中使用非静态方法中的内容时会报错
public static void setCity(String c) {
city = c;
}
}
public class TestStatic {
// 运行本程序时,静态代码块会被自动执行
static {
System.out.println("3.TestStatic 类的静态代码块被调用! ");
}
public static void main(String[] args) {
System.out.println("4.程序开始执行! ");
// 产生两个实例化对象
Person p1 = new Person("小明", 25);
Person p2 = new Person("小红", 23);
System.out.println("修改之前信息: " + p1.talk());
System.out.println("修改之前信息: " + p2.talk());
System.out.println(" **************修改之后信息**************");
// 修改后的信息
Person.setCity("上海");// 静态方法可以用类名直接调用
System.out.println("修改之后信息: " + p1.talk());
System.out.println("修改之后信息: " + p2.talk());
}
}
输出结果为:
3.TestStatic 类的静态代码块被调用!
4.程序开始执行!
2.Person 类的静态代码块被调用!
修改之前信息: 我是:小明,今年:25岁,来自:北京
修改之前信息: 我是:小红,今年:23岁,来自:北京
**************修改之后信息**************
修改之后信息: 我是:小明,今年:25岁,来自:上海
修改之后信息: 我是:小红,今年:23岁,来自:上海
由以上程序可以得出,static关键字可以用于修饰变量、方法和代码块。静态变量被所有对象共享。静态方法中不可以使用非静态内容,当函数功能没有访问到对象的特有内容时就可以定义为静态。静态代码块用于给类进行初始化,会先执行。
6、内部类
分析事物时,发现该事物描述中还有事物,而且这个事物还在访问被描述事物的内容。这时就是还有的事物定义成内部类来描述。内部类可以直接访问外部类中的成员。外部类要访问内部类,必须建立内部类的对象。
//内部类总结
class Outer {
int score = 95;
// 外部类可以访问内部类中的成员,内部类持有了外部类的引用: 外部类名.this
void inst() {
Inner in = new Inner();
in.display();
}
// 内部类在局部位置上只能访问局部中被final修饰的局部变量。
void inst1(final int s) {
final int temp = 20;
class Inner1 {
void show() {
System.out.println("成绩1:score=" + (score + s + temp));
}
}
Inner1 in = new Inner1();
in.show();
}
// static class Inner{}
// 用 static 声明的内部类则变成外部类,但是用 static 声明的内部类不能访问非 static 的外部类属性
public class Inner {
void display() {
// 在内部类中声明一name属性
// String name = "小明";
System.out.println("成绩: score = " + score);// Outer.this.score
}
// static void function(){//如果内部类中定义了静态成员,该内部类也必须是静态的。
// System.out.println("function run ...."+score); }
}
// 在此调用内部类的name属性,会产生错误,外部类不能访问内部类中的属性 public void print(){
// System.out.println("姓名:"+name); }
}
public class InnerClassDemo {
public static void main(String[] args) {
Outer out = new Outer();
out.inst();
// 直接访问外部类中的内部类中的成员。
Outer.Inner in = new Outer().new Inner();
in.display();
// 如果内部类是静态的。 相当于一个外部类
// Outer.Inner in = new Outer.Inner();
// in.display();
// 如果内部类是静态的,成员是静态的。
// Outer.Inner.function();
out.inst1(5);
}
}
输出结果为:
成绩: score = 95
成绩: score = 95
成绩1:score=120
二、继 承
1、继承相关概念
java中继承用到extends关键字。当类与类之间存在着所属关系(is-a)时,就定义继承。被继承的类成为父类或超类,继承得到的新类成为子类或派生类。父类是子类不断向上抽取出来的。如:class Students(子类) extends Person(父类)。子类会继承父类的所有属性和方法。
java中不允许多继承,即一个子类不允许有多个父类。但是允许多层继承,即C继承B,B继承A,就出现了继承体系。
2、子类继承父类的特性
2.1 子类实例化
一个对象实例化过程:
Person p = new Person();
- JVM会读取指定的路径下的Person.class文件,并加载进内存,并会先加载Person的父类(如果有直接的父类的情况下);
- 在堆内存中的开辟空间,分配地址;
- 并在对象空间中,对对象中的属性进行默认初始化;
- 调用对应的构造函数进行初始化;
- 在构造函数中,第一行会先到调用父类中构造函数进行初始化;
- 父类初始化完毕后,在对子类的属性进行显示初始化;
- 在进行子类构造函数的特定初始化;
- 初始化完毕后,将地址值赋值给引用变量。
2.2 super关键字:用于子类中,调用父类中的构造方法,此时只能放在子类程序的第一行。另外可以通过(super.父类中的属性或方法)来调用父类的内容。但是子类不能访问父类中的私有内容。super关键字与this关键字调用构造函数的操作是不能同时出现的。
2.3 覆盖
当子父类中出现成员函数一模一样的情况,会运行子类的函数。这种现象,称为覆盖操作。当对一个类进行子类的扩展时,子类需要保留父类的功能声明,但是要定义子类中该功能的特有内容时,就使用覆盖操作完成。这时函数在子父类中的的两个特性:
- 重载。同一个类中。overload
- 覆盖。子类中。覆盖也称为重写,覆写。override
//继承总结
class Person {
String name;
int age;
// 父类中构造函数
public Person() {
System.out.println("1.public Person(){}");
}
// 父类中构造函数
public Person(String name, int age) {
// this关键字代表当前对象
this.name = name;
this.age = age;
}
// 父类中的方法
public String talk() {
// this调用本类中的内容
return "我是: " + this.name + ",今年: " + this.age + "岁 ";
}
}
// Student类继承于Person类
class Student extends Person {
String school;
// 子类中的构造函数
public Student() {
// super();隐含super调用父类中的空参数构造函数
System.out.println("2.public Student(){}");
}
public Student(String name, int age, String school) {
// 分别为属性赋值
this.name = name;
this.age = age;
this.school = school;
}
// 此处复写 Person 类中的 talk()方法,并用super调用父类中的talk方法
public String talk() {
return super.talk() + ",我在" + this.school + "上学";
}
}
class ExtendsDemo2 {
public static void main(String[] args) {
Student s = new Student();
Student ss = new Student("小明", 23, "北京");
// 此时调用的是子类中的 talk()方法
System.out.println(ss.talk());
}
}
输出结果为:
1.public Person(){}
2.public Student(){}
1.public Person(){}
我是: 小明,今年: 23岁 ,我在北京上学
三、抽象类
抽象类定义规则
- 抽象类和抽象方法都必须用 abstract 关键字来修饰。
- 抽象类不能被实例化,也就是不能用 new 关键字去产生对象。
- 抽象方法只需声明,而不需实现。
- 含有抽象方法的类必须被声明为抽象类,抽象类的子类必须复写所有的抽象方法后才能被实例化,否则这个子类还是个抽象类。
//抽象类
abstract class Person {
String name;
int age;
String occupation;
//抽象类中定义构造函数
public Person(String name, int age, String occupation) {
this.name = name;
this.age = age;
this.occupation = occupation;
}
// 定义抽象方法 talk()
public abstract String talk();
}
// Student 类继承自 Person 类
class Student extends Person {
public Student(String name, int age, String occupation) {
//调用抽象类中的构造函数
super(name, age, occupation);
}
//覆盖 talk()方法
public String talk() {
return "学生的姓名: " + this.name + ",年龄: " + this.age + ",职业:"
+ this.occupation + "! ";
}
}
// Worker 类继承自 Person 类
class Worker extends Person {
public Worker(String name, int age, String occupation) {
//调用抽象类中的构造函数
super(name, age, occupation);
}
// 覆盖 talk()方法
public String talk() {
return "工人的姓名: " + this.name + ",年龄: " + this.age + ",职业:"
+ this.occupation + "! ";
}
}
class AbstractDemo {
public static void main(String[] args) {
Student s = new Student("小明", 20, "学生");//创建Student对象
Worker w = new Worker("小强", 28, "工人");//创建Worker对象
System.out.println(s.talk());//调用的方法
System.out.println(w.talk());//调用的方法
}
}
输出结果为:
学生的姓名: 小明,年龄: 20,职业:学生! 工人的姓名: 小强,年龄: 28,职业:工人!
四、接 口
当一个抽象类中的方法都是抽象的时候,这时可以将该抽象类用另一种形式定义和表示,就是 接口( interface)。接口里的数据成员必须初始化,且数据成员均为常量。接口里的方法必须全部声明为 abstract,也就是说,接口不能像抽象类一样有一般方法,而必须全部是“抽象方法”。对于接口当中的成员都有固定的修饰符。全局常量: public static final ;抽象方法。public abstract。接口是java实现多继承的一种机制,它可以通过多实现来达到多继承的效果。
//定义接口
interface A {
int i = 10;//public static final int i = 10;
public void sayI();//public abstract void sayI();
}
interface E {
int x = 40;
public void sayE();
}
// B 同时继承了 A、 E 两个接口
interface B extends A, E {
int j = 20;
public void sayJ();
}
// C 继承实现 B 接口,也就意味着要实现 A、 B、 E 三个接口的抽象方法
class C implements B {
public void sayI() {
System.out.println("i = " + i);
}
public void sayJ() {
System.out.println("j = " + j);
}
public void sayE() {
System.out.println("e = " + x);
}
}
class InterfaceDemo {
public static void main(String[] args) {
C c = new C();
c.sayI();
c.sayJ();
c.sayE();
}
}
输出结果为:
i = 10
j = 20
e = 40
五、多 态
一个对象对应着不同类型即为多态。如动物对象里有猫和狗两种形态。在java中多态体现在父类或接口的引用指向其子类对象。多态的存在提高了代码的扩展性,但是使用多态后前期定义的内容不能使用(调用)后期子类的特有内容。多态涉及两个转型:向上转型和向下转型。向上转型会自动完成,向下转型需要进行强制类型转换。
//定义多态
abstract class Person {
abstract void talk();
}
//American类继承Person类
class American extends Person {
void talk() {
System.out.println("说英语");
}
void playbasketball() {
System.out.println("打篮球");
}
}
//Japanese类继承Person类
class Japanese extends Person {
void talk() {
System.out.println("说日语");
}
void tea() {
System.out.println("喝茶");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
Person a = new American(); // 向上转型,隐藏子类的特有内容。。
American c = (American) a;// 向下转型的目的是为了使用子类中的特有方法。
c.talk();
c.playbasketball();
// 对于转型,自始自终都是子类对象在做着类型的变化。
// Person a1 = new Japanese();
// Japanese c1 = (Japanese)a1;//ClassCastException
method(new Japanese());
}
public static void method(Person p) {
p.talk();
// instanceof:用于判断对象的具体类型。只能用于引用数据类型判断,通常在向下转型前用于健壮性的判断。
if (p instanceof American) {
American a = (American) p;
a.playbasketball();
} else if (p instanceof Japanese) {
Japanese j = (Japanese) p;
j.tea();
} else {
}
}
}
输出结果为:
说英语
打篮球
说日语
喝茶