1.代码块
代码块定义:使用"{}"定义的一段代码
根据代码块的位置以及关键字,可以简单分
为以下四种:
a.普通代码块
b.构造块
c.静态块
d.同步代码块
普通代码块
定义:定义在方法中的代码块
public class Test1{
public static void main(String[] args){
//直接用{}定义,普通方法块
{
int x = 10;
System.out.println("x="+x);
}
int x = 100;
System.out.println("x="+x);
}
}
构造块
定义:定义在类中的代码块
class Student{
//定义在类中,不加任何修饰
{
System.out.println("student类的构造块");
}
public Student(){
System.out.println("Student类的构造方法");
}
}
public class Test{
public static void main(String[] args){
new Student();
new Student();
}
}
通过以上代码的执行结果可以看出:在对象产生时,构造块优先于构造方法执行,有几个对象产生就调用几次构造块。
在构造方法执行前完成一些属性的初始化操作,也可以进行简单地逻辑解释
静态代码块
定义:使用static修饰的代码块
根据所在的类不同分为以下:
在非主类中的静态代码块
class Student{
//定义在类中,不加任何修饰
{
System.out.println("student类的构造块");
}
public Student(){
System.out.println("Student类的构造方法");
}
//定义在非主类中的静态块
static {
System.out.println("Sudent类的静态块");
}
}
public class Test{
public static void main(String[] args){
System.out.println("主方法开始");
new Student();
new Student();
System.out.println("主方法结束");
}
}
通过以上代码执行结果可以看出:静态库优先于构造块执行,并且屋里产生几个实例化对象静态块只执行一次
在主类中的静态块
public class Test{
{
System.out.println("主类的构造块");
}
public Test(){
System.out.println("主类的构造方法");
}
static {
System.out.println("主类的静态块");
}
public static void main(String[] args){
System.out.println()
new Test();
new Test();
}
}
由以上代码的运行结果可以看出:主类中的静态块优先于主方法执行
内部类的定义与使用
内部类的概念:所谓内部类就是在一个类的内部进行其他类结构的嵌套操作
class Person{
private String msg = "Hello World";
//定义一个内部类
class Student{
//内部类中定义一个普通方法
public void print(){
System.out.println(msg);
}
}
//外部类中定义一个普通方法,调用内部类的print方法
public void fun(){
Student stu = new Student();//内部类对象
stu.print();//内部类对象调用内部类提供的方法
}
}
public class Test{
public static void main(String[] args){
//外部类对象
Person per = new Person();
//外部类对象调用外部类方法
per.fun();
}
}
上述代码就是内部类的简单定义实例,可以看出程序的结构有些乱,但是内部类可以方便地操作外部类的私有访问属性
将内部类拆分出来:
class Person{
private String msg = "Hello World";
public String getMsg() {//设置get方法取得msg的属性
return msg;
}
public void fun(){//Person类对象可以调用这个方法
Student stu = new Student(this);//this表示当前对象
stu.print();//调用Student类方法
}
}
class Student{
private Person per;
public Student(Person per){
this.per = per;
}
public void print(){
System.out.println(per.getMsg());
}
}
public class Test{
public static void main(String[] args){
Person per = new Person();//实例化Person对象
per.fun();
}
}
内部类的产生原因:
a.内部类方法可以访问该类定义所在作用于的数据,包括private修饰的私有数据
b.内部类可以对同一包下的其他类不可见
c.内部类可以实现Java单继承缺陷
d.当我们想要定义一个回调函数缺不行写太多代码的时候,可以使用匿名内部类实现
内部类实现Java多继承
class A{
private String name = "A类的私有属性";
public String getName() {
return name;
}
}
class B{
private int age = 10;
public int getAge() {
return age;
}
}
class Person{
private class StudentA extends A{
public String name(){
return super.getName();
}
}
private class StudentB extends B{
public int age(){
return super.getAge();
}
}
public String name(){
return new StudentA().name();
}
public int age(){
return new StudentB().age();
}
}
public class Test{
public static void main(String[] args){
Person per = new Person();
System.out.println(per.name());
System.out.println(per.age());
}
}
内部类与外部类的关系
1.对于非静态内部类,内部类的创建依赖外部类的实例化对象,没有外部类实例化之前无法创建内部类
2.内部类是一个相对独立的个体,与外部类没有is-a关系
3.内部类可以直接访问外部类的元素(包含私有属性),外部必须通过内部类引用间接访问内部类元素
内部类直接访问外部类元素
class Outter{
private String outName;
private int outAge;
class Inner{
private int inAge;
public Inner(){
Outter.this.outName = "我是一个外部类";
Outter.this.outAge = 20;
}
public void disPlay(){
System.out.println(outName);
System.out.println(outAge);
}
}
}
public class Test{
public static void main(String[] args){
Outter.Inner inner = new Outter().new Inner();
inner.disPlay();
}
}
外部类间接访问内部类元素
class Outter{
public void display(){
//外部类通过内部类引用来访问内部类元素
Inner inner = new Inner();
inner.display();
}
class Inner{
public void display(){
System.out.println("我是一个内部类");
}
}
}
public class Test{
public static void main(String[] args){
Outter out = new Outter();
out.display();
}
}
创建一个内部类对象
1.在外部类外部创建内部类对象语法:
外部类.内部类 内部类对象 = new 外部类().new 内部类();
Outter.Inner in = new Outter().new Inner();
2.在外部类内部创建内部类对象
内部类 内部类对象 = new 内部类();
Inner in = new Inner();
内部类的分类
在Java中内部类一般分为成员内部类、静态内部类、方法内部类、匿名内部类
成员内部类:
成员内部类不存在任何static变量和方法
成员内部类依附于外围类,只有先创建了外围类才能够创建内部类
静态内部类:
static关键字可以修饰成员变量、方法、代码块、还可以修饰内部类,使用static修饰的内部类称为静态内部类。
静态那我不来与非静态内部类最大的区别在于,非静态内部类在编译完成之后会隐含地保存一个引用,该引用指向创建它的外围类,但是静态内部类没有
所以,静态内部类的创建不需依赖外围类,可以直接创建;静态内部类不可以使用任何外围类的非static成员变量和方法。
静态内部类对象的创建语法:
外部类.内部类 内部类对象 = new 外部类.内部类()
class Outer{
private static String msg = "Hello World";
static class Inner{//定义一个静态内部类
public void print(){
System.out.println(msg);//调用外部类的msg属性
}
}
public void fun(){
Inner in = new Inner();//内部类对象
in.print();//调用内部类方法
}
}
public class Test {
public static void main(String[] args){
Outer.Inner in = new Outer.Inner();
in.print();
}
}
方法内部类()局部内部类
方法内部类定义在外部类方法中,局部内部类和成员内部类基本一致,只是他们的作用域不同,方法内部类只能在该方法中使用,出了该方法就会失效。
在解决某些比较复杂的问题时,想要创建一个类来辅助我们的解决方案,但又不希望这个类是公共可用的,所以就产生了局部内部类
a.局部内部类不允许使用权限修饰符(public、private、protected)
b.局部内部类对外完全隐藏,除了创建这个类的方法可以访问其他地方均不允许访问
c.局部内部类要想使用方法形参,该形参必须用final声明
class Outer{
private int num;
public void display(final int test){
class Inner{//局部内部类
private void fun(){
num++;
System.out.println(num);
System.out.println(test);//局部内部类使用方法形参,test用final声明
}
}
new Inner().fun();//在内部类的外部调用内部类方法
}
}
public class Test {
public static void main(String[] args){
Outer out = new Outer();//创建外部类对象
out.display(25);
}
}
匿名内部类
概念:匿名内部类就是一个没有名字的内部类,所以它符合方法内部类的所有约束。
特征:
a.匿名内部类没有任何修饰符
b.匿名内部类必须继承一个抽象类或者一个接口
c.匿名内部类中不能存在任何静态成员或方法
d.匿名内部类没有构造方法,因为它没有类名
e.与局部内部类相同,匿名内部类也可以引用方法形参,该形参必须使用fianl声明
interface MyInterface{
void test();
}
class Outer{
private int num;
public void display(final int num){
//匿名内部类,实现MyInterface接口
new MyInterface(){
@Override
public void test(){
System.out.println("匿名内部类"+num);
}
}.test();
}
}
public class Test {
public static void main(String[] args){
Outer out = new Outer();
out.display(22);
}
}
3.继承的定义与使用
面向对象的第二大特征:继承,继承的主要优势在于,在已有累的基础上继续进行功能的扩充
继承可以消除结构定义上的重复,避免大量重复代码的出现
继承的实现:class 子类(派生类) extends 父类(超类)
继承的基本实现:
class Person{//定义父类结构
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Student extends Person{//定义一个子类
}
public class Test {
public static void main(String[] args){
Student stu = new Student();
stu.setName("张三");
stu.setAge(22);
System.out.println("姓名:"+stu.getName()+",年龄:"+stu.getAge());
}
}
当子类发生了类继承关系之后,子类可以直接使用父类的操作,实现了代码的重用,同时子类可以进行功能上的扩充
class Student extends Person{//子类继承父类
private String school;//子类扩充学校属性
public String getSchool() {//扩充get,set方法
return school;
}
public void setSchool(String school) {
this.school = school;
}
}
public class Test {
public static void main(String[] args){
Student stu = new Student();
stu.setName("张三");
stu.setAge(22);
stu.setSchool("希望小学");
System.out.println("学校:"+stu.getSchool()+",姓名:"+stu.getName()+",年龄:"+stu.getAge());
}
}
继承的限制:子类对象在实例化之前一定会首先实例化父类对象,默认调用父类的构造方法后在调用子类构造方法进行初始化
class Person{//定义父类结构
public Person(){
System.out.println("Person类对象产生");
}
}
class Student extends Person{//定义一个子类
public Student(){
System.out.println("Student类对象产生");
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student();
//Person类对象产生
//Student类对象产生
}
}
实际上在子类的构造方法中,隐含了一个super();
如果父类没有提供无参构造,那么必须使用super();明确表示要调用的父类构造方法
Java值允许单继承,不能多继承。一个子类只能继承一个父类
可以使用多层继承的形式来实现多继承
class A{}
class B extends A{}//B类继承A类
class C extends B{}//C类继承B类
在进行继承时,子类会继承父类的所有结构(包含私有属性、构造方法、普通方法)
但是所有的非私有属性可以直接调用(属于显示继承),私有属性属于隐式继承,必须通过getter或setter方法来调用。
class Person{//定义父类结构
private String name;
public String getName() {//子类可调用方法
return name;
}
public void setName(String name) {//子类可调用方法
this.name = name;
}
}
class Student extends Person{//定义一个子类
public void fun(){
System.out.println(this.getName());
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student();
stu.setName("张三");
stu.fun();
}
}
继承总结:
a.继承的目的是扩展已有的类,使代码重复利用
b.子类对象数理化之前,不管如何操作一定会先实例化父类
c.不可以多重继承,但是允许多层继承
4、覆写
覆写概念:如果子类定义了与父类完全相同的方法或熟悉属性时,这样的操作就是覆写
方法覆写:子类定义了与父类方法名称、参数类型及个数完全相同的方法。但是覆写时不能拥有比父类更为严格的访问控制权限
三种访问控制权限:private<default<public,就是说如果父类使用public 那么子类必须也使用public
class Person{//定义父类结构
public void print(){
System.out.println("父类的普通方法输出");
}
}
class Student extends Person{//定义一个子类
public void print(){
System.out.println("子类的普通方法输出");
}
}
public class Test {
public static void main(String[] args) {
new Student().print();//子类的普通方法输出
}
}
在进行覆写操作时需要特别注意:当前使用的对象是通过哪个类new出来的
调用某个方法时,如果该方法已经被子类覆写,那么调用的一定是被付下过得方法
如果父类使用private修饰方法、子类使用public修饰方法,此时不存在方法覆写。
父类方法用private定义,表示该方法只能被父类使用,子类不知道父类有这样的方法,更不可能覆写
class Person{
public void fun(){
this.print();
}
//如果现在父类方法使用了private定义,那么就表示该方法只能被父类使用,子类无法使用。换言之,子类根本就不知道父类有这样的方法。
private void print(){
System.out.println("1.[Person]类的print方法");
}
}
class Student extends Person{
//这个时候该方法只是子类定义的新方法而已,并没有和父类的方法有任何关系。
public void print(){
System.out.println("2.[Student]类的print方法");
}
}
public class Test{
public static void main(String[] args) {
new Student().fun();//1.[Person]类的print方法
}
}
属性覆写
当子类定义了一个与父类属性美年广场完全相同的属性时,就称为属性覆写
lass Person{
public String name = "小李";
}
class Student extends Person{
public String name = "小花";
}
public class Test{
public static void main(String[] args) {
System.out.println(new Student().name);//小花
}
}
super关键字的用法
使用super调用父类的同名方法
class Person{
public String name = "小李";
public void print(){
System.out.println(name);
}
}
class Student extends Person{
public String name = "小花";
public void print(){
super.print();//调用父类方法
System.out.println(name);
}
}
public class Test{
public static void main(String[] args) {
new Student().print();//小李 小花
}
}
使用super调用父类属性
class Person{
public String name = "父类";
public void print(){
System.out.println(name);
}
}
class Student extends Person{
public String name = "子类";
public void print(){
System.out.println(super.name);//调用父类属性
System.out.println(this.name);
}
}
public class Test{
public static void main(String[] args) {
new Student().print();//父类 子类
}
}
5.final关键字
在Java中final被称为终结器,可以使用final定义类、方法、属性
使用(String类就是final定义的)
final class A{}//不能有子类
使用final定义的方法不能被子类覆写
class A{
public final void fun(){}
}
使用final定义的变量就成为了常量,常量必须在大亨们时赋值,并且不能被修改
关于final:
a.final关键字可以用于成员变量、本地变量、方法以及类
b.final成员变量必须在声明的时候初始化或者在构造器中初始化
public final int AGE = 18;
c.final变量不能再次赋值、本地变量必须在声明时赋值、final方法不能被覆写、final类不能被继承
6.多态性
多态的核心表现:
a.方法的多态性:
方法重载:同一个方法名称可以根据参数类型不同或个数不同调用不同的方法
方法覆写:同一个父类非,可以根据资料不同实例化有不同的实现
b.对象的多态性:(方法覆写为前提)
向上转型:父类 父类对象 = 子类实例(自动)
向下转型:子类 子类对象 = (子类)父类实例(强制)
向上转型:
class Person{
public void print(){
System.out.println("我是爸爸!");
}
}
class Student extends Person{
public void print(){
System.out.println("我是儿子!");
}
}
public class Test{
public static void main(String[] args) {
Person per = new Student(); //向上转型
per.print();
}
}
不管是否发生了向上转型,核心本质还是在于:你使用的是哪一个子类(new在哪里),而且调用的方法是否被子类所覆写了。
向下转型:
向下转型指的是将父类对象变为子类对象,当你需要子类扩充操作的时候就要采用向下转型
class Person{
public void print(){
System.out.println("1.我是爸爸!");
}
}
class Student extends Person{
public void print(){
System.out.println("2.我是儿子!");
}
public void fun(){
System.out.println("只有儿子有!");
}
}
public class Test{
public static void main(String[] args) {
Person per = new Student();
per.print();
//这个时候父类能够调用的方法只能是本类定义好的方法
//所以并没有Student类中的fun()方法,那么只能够进行向下转型处理
Student stu = (Student) per;
stu.fun();
}
}
多态性总结:
对象多态性的核心在于方法的覆写。
通过对象的向上转型可以实现接收参数的统一,向下转型可以实现子类扩充方法的调用(一般不操作向下转型,有安全隐患)。
两个没有关系的类对象是不能够进行转型的,一定会产生ClassCastException