02-JAVAOOP

02-JavaOOP


目录:

01:什么是面向对象

02:什么是类什么是对象

03:面向对象的三大特征

04:抽象类、接口、匿名内部类

05:内部类间的区别

06:重载和重写的区别

07:编译时和运行时的区别

08:重写,重载,泛型,分别是在运行时还是编译时执行?

09:静态属性、静态代码块块、非静态属性、非静态代码块块、构造函数在初始化时的执行顺序?

10:23种设计模式

11:单例设计模式

12:abstract为什么不能与private,final同时使用?

13:super和this的异同

14:成员变量(实例变量)&局部变量&静态变量的区别


01:什么是面向对象

1.1 面向对象的概述

    “面向对象是一种以事物为中心的编程思想。是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。面向对象时相对于面向过程而已的(c则是一个典型的面向过程的语言),站在面向对象的角度去看问题,你则是对象的动作的指挥者。如果站在面向过程的角度去看问题,你则是动作的执行者。

1.2面向对象(java语言)与面向过程(C语言)对比

  “万物皆对象”。
  1:买电脑
    1:面向过程
       1:查资料
      2:电脑城砍价
      3:被黑
      4:痛苦归来
    2:面向对象
      1:找对象。老师
      2:老师.砍价
      3:老师.检测电脑
      4:电脑成功购买
  2:吃饭
    1:面向过程
      1:自己动手做
      2:买菜
      3:洗菜
      4:煮饭炒菜
      5:正在吃饭
    2:面向对象
      1:找专业对象
      2:餐馆.点餐
      3:餐馆,做饭
      4:正在吃饭
    等等............

1.3 面向过程

强调的是功能行为,面向过程”是一种以过程为中心的编程思想。“面向过程”他们不支持丰富的“面向对象”特性(比如继承、多态),就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。面向过程在这一系列工作的执行中,强调的是工作的执行。

02:什么是类什么是对象

类与对象时整个面向对象中最基础的组成单元。
:是抽象的概念集合,表示的是一个共性的产物,类之中定义的是属性和行为(方法);
对象:对象是一种个性的表示,表示一个独立的个体,每个对象拥有自己独立的属性,依靠属性来区分不同对象。
可以一句话来总结出类和对象的区别:类是对象的模板,对象是类的实例。类只有通过对象才可以使用,而在开发之中应该先产生类,之后再产生对象。类不能直接使用,对象是可以直接使用的。

03:面向对象的三大特征

一、继承(Inheritance,也称为泛化)

        继承是面向对象编程实现软件复用的重要手段,当子类继承父类之后,将会自动获得父类的属性和方法,不需要自己再重新写一段一模一样的代码。同时,子类也可以增加自己的属性和方法,甚至还可以重新定义父类的属性、重写父类的方法,获得与父类不同的功能。
        在类层次结构中,修改父类的属性和方法会自动的反映在它所有的子类、子类的子类中,因为他们通过继承父类从而自动接收新的内容。父类也被叫做“超类”或者“基类”,子类也被叫做派生类。从上述可以得知,继承有利于软件的复用,避免重复代码的出现,防止多次修改,从而提高开发效率。
        注意:子类继承的是父类的非静态方法和属性,并不能继承父类的静态方法、静态常量和构造方法。另外,子类不用显式的调用super(),系统会自动调用父类的无参构造方法。
        不能继承父类的静态方法或静态常量,是因为:程序在执行时,类就已经被JVM分配到方法区中,而对象只有在被实例化时JVM才会为其分配空间,所以两者的分配的空间并不相同。另外,静态的方法或变量只会分配一次,而对象的实例化则不同,每实例化一个对象,JVM都会为该对象分配一次内存空间。
        不能继承父类的构造函数,是因为:构造函数是一个特殊的函数,它必须和类同名,用来初始化实例对象。无论是子类还是父类都必须存在一个构造函数,倘若两者存在相同的构造函数,那么程序到底调用那一个构造函数,从而实例化对象?换句话来说,老子的东西还是老子的,儿子的东西才是儿子的,所以不能发生冲突。
        继承是面向对象技术的一大特点。子类继承了父类之后,就拥有了父类所有的属性和方法;子类可以覆盖父类的方法,也可以对其进行重载。开发人员可以根据自己的需要,在继承类中添加相应的属性和方法,以完成类的进化和升级。
        重写:在父子类继承的情况下,子类写出一个跟父类一模一样的方法,方法体内可以修改,就叫方法重写。重写的好处在于子类可以根据需要,定义特定于自己的行为。也就是说子类能够根据需要重写所继承父类的方法。
//父类
class Animate{
public void eat(){
System.out.println("宠物在吃饭");
}
}
//子类
class Dog extends Animate{
public void eat(){
System.out.println("狗在吃饭");
}
}
        注意:子类覆盖方法的访问权限要不小于父类中被覆盖方法的访问权限。
        重载:重载时面向对象语言中一个很重要的特性,它是以一种统一的方法来处理不同情况的机制,即一个类中可以有多个相同名称的方法,这些方法对应不同的参数。
public void run(){
System.out.println("跑步");
}
public void run(String name){
System.out.println(name + "正在跑步");
}

二、封装(Encapsulation)

        封装是将对象的实现细节(属性或方法)隐藏起来,然后通过对象来调用外部方法。处于安全的角度来说,封装可以使设置为私有类型(private)的对象的状态信息隐藏在类的内部中,不允许外部程序直接访问对象的内部消息,只能通过类中提供的外部方法实现对内部信息的操作与访问。
        那么问题来了,如何将属性或方法隐藏起来呢?Java为我们提供了操作符,操作符分为访问控制符和非访问控制符。所以我们肯定知道,这里我们所讲的就是访问控制符。访问控制符有四种,它们之间的访问域均有不同,如果下图所示。
访问控制符
作用域 
  当前类
同包
子类
  其他
public
protected  
  ×
default
  ×
  ×
private 
  ×
  ×
  ×
       注意:类的控制级别只有public与default,而成员变量与方法4种都有。如果类的构造方法为private,则其他类均不能生成该类的实例,只能在该类的入口函数中内部创建实例对象,但是这就违背了一些初衷了。
//类Person
public class Person{
private String name = "vincent";
private String sex = "男";
private int age = 20;
public String getName() {
return name;
}
public String getSex() {
return sex;
}
public int getAge() {
return age;
}
}
//测试类TestMain
public class TestMain{
public static void main(String[] args){
Person sty = new Person();
//只允许访问而不能操作
String name = sty.getName();
String sex = sty.getSex();
Int age = sty.getAge();
System.out.println("姓名:" + name);
System.out.println("性别:" + sex);
System.out.println("年龄:" + age);
}
}

三、多态(Polymorphism)

        多态是建立在继承的基础上的,是指子类类型的对象可以赋值给父类类型的引用变量,但运行时仍表现为子类的行为特征。
        Java引用变量(即引用对象)有两个类型,一种是编译时的类型,另外一种是运行时的类型。编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。
        如果运行时和编译时的类型不一致,那么就可能会出现所谓的多态。为什么要说可能而不是一定呢?这是因为多态有三个必要条件:
        ①、要有继承关系或实现接口
        ②、要有方法重写
        ③、父类引用指向子类对象 或 接口引用指向实现类对象
        只有满足上面三种条件,才有可能出现多态。当使用多态的方式调用方法时,首先检查父类中是否存在该方法,如果没有则报错;如果有,再去调用子类中同名的方法。
        要理解多态我们就必须要明白什么是“向上转型”和”向下转型”。我们定义如下代码:父类Animate、子类Dog、测试类DogTest,来看看当父类引用对象指向子类实例对象时,输出的结果会怎么样。
//父类Animate
class Animate {
String name = "动物";
static int age = 20;
public void eat() {
System.out.println("动物吃饭");
}
public static void sleep() {
System.out.println("动物在睡觉");
}
public void play(){
System.out.println("动物在玩耍");
}
}
//子类Dog
public class Dog extends Animate{
String name = "WangCai";
static int age = 4;
public void eat() {
System.out.println("狗在吃饭");
}
public static void sleep() {
System.out.println("狗在睡觉");
}
public void Demolish() {
System.out.println("狗在拆家");
}
}
//测试类DogTest
public class DogTest{
public static void main(String[] args) {
Animate Anm = new Dog();
Anm.eat();          //子类重写的方法
Anm.sleep();        //子类重写的静态方法
Anm.play();         //子类重写的方法

System.out.println(Anm.name);
System.out.println(Anm.age);
}
}
        代码中,我们定义了一个Animate类型的Anm变量对象,它指向Dog的实例对象。由于Dog是继承Animate的,所以Dog可以自动向上转型为Animate。我们知道在继承中,子类继承了父类的属性和方法,还可能额外扩展了父类的属性和方法。所以当我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。
        但是向上转型是有缺点的,就是它必定会导致一些方法和属性的丢失,从而导致我们不能够获取它们。所以,父类类型的引用能调用父类中定义的所有属性和方法,对于存在子类中的静态方法和所有属性它只能舍弃(这里并没有放弃普通方法)。
        由于面向对象的继承特性,子类重写父类的非静态方法会覆盖掉父类的方法,而静态方法在程序运行时存储的地址不同。所以,当向上转型时,子类的静态方法无法覆盖父类的静态方法,从而调用的是父类的静态方法。
        对于多态我们可以总结为:指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,无法调用子类独有的方法和属性。对于父类的成员变量无法被子类覆盖,因此需要父类拥有setter/getter方法,然后子类再重写以便就可以获取子类的成员变量;而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的非静态方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。
 
//父类Animate
class Animate {
String name = "动物";
static int age = 20;
public String getName() {
return name;
}
public static int getAge() {
return age;
}
}
//子类Dog
public class Dog extends Animate{
String name = "WangCai";
static int age = 4;
public String getName() {
return name;
}
public static int getAge() {
return age;
}
}
//测试类DogTest
public class DogTest{
public static void main(String[] args) {
Animate Anm = new Dog();
//直接访问属性
System.out.println(Anm.name);
System.out.println(Anm.age);
System.out.println("-----------");
//通过get/set方法返回属性值
System.out.println(Anm.getName());
System.out.println(Anm.getAge());
}
}

04:抽象类、接口、匿名内部类

        对于面向对象编程来说,抽象是它的一大特征之一。在Java可以通过两种形式来体现面向对象编程(简称:OOP)的抽象:接口和抽象类。这两者既有相似的地方、又有不同的地方。在了解接口和抽象类之前,先了解一下什么是抽象方法。
         抽象方法是一种特殊的方法:它只有方法的定义,而没有具体的实现(方法体)。如果子类不是抽象类,那么父类的抽象方法必须由子类来实现,否则程序会报错。抽象方法的声明格式为:abstract void 类名();
         抽象方法必须使用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类。抽象类也必须在类前,用abstract关键字修饰。注意:抽象类不一定必须含有抽象方法。但如果一个抽象类不包含抽象方法,那为何还要设计为抽象类?

抽象类 (abstract)

         抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。从多个具有相同特征的类中抽象出来的一个抽象类。以这个抽象类做为子类的模板,避免子类设计的随意性,体现了一种模板模式的设计。抽象类做为多个子类的通用模板,子类可以在抽象类的基础上进行扩展和改造。
注意:①、Java允许类、接口或者成员方法具有抽象属性,但不允许成员域或构造方法具有抽象属性;
         ②、如果一个类不具有抽象属性,则不能在该类的类体中定义抽象成员方法;
         ③、抽象类允许存在构造方法,但是不能初始化实例对象,即抽象类不能创建实例对象。抽象类的构造函数只有在子类实例化对象时才会被调用。
         ④、添加了static、final、private修饰符的方法与构造方法不能被声明为抽象方法。因为该方法不会被子类继承,子类自然也无法实现父类抽象方法的具体内容,从而导致程序报错。
         ⑤、抽象类中既可以有正常方法,也可以有抽象方法,甚至完全没有抽象方法也行,但有抽象方法的类必须是抽象类。

接口(interface)

        接口相当于抽象类的变体,在接口中,所有方法都是抽象的。接口就是标准(一些类需要遵循的规范),用来隔离具体的实现。程序接口的使用,将调用者和提供者之间进行了解耦,只要实现者遵循这个接口来做就好,实现的细节不用管。
        举个例子:现在的电脑、充电宝、U盘和手机等等都具有USB接口。这些产品的生产商只需要遵循USB的国际标准就可以实现不同产品的对接,而不用为了兼容不同的设备去生存不同的USB接口。
        注意 : ①、接口不是类,不存在构造函数,所以也无法被实例化。
               ②、接口内的所有属性默认为public static final,只能在定义时指定默认值。
               ③、接口内的所有方法默认为public abstract,不能用static和final。
               ④、接口内不允许有正常的方法。
               ⑤、接口可以同时继承多个父接口,但接口只能继承接口,不能继承类。
        接口和类不同,定义接口不再使用class关键字,而是使用interface关键字。如果接口没有使用public修饰符,这默认采用包权限访问控制符,即只有在相同包的结构下才能访问该接口。由于接口定义的是一种规范,他是一种更彻底的抽象类。因此,接口里不能包含构造器和初始化块定义。接口里可以包含:常量属性、抽象方法(无方法体)、内部类(包括内部接口)和枚举类定义。
        接口的继承和类继承不一样, 接口完全支持多继承,即一个接口可以有多个直接父接口。一个接口继承多个父接口时,多个父接口排在extends关键字之后,每个接口名之间用逗号隔开。与类继承相似,子接口将会获得父接口里定义的所有抽象方法、常量属性、内部类和枚举定义。
        接口不能用于创建实例,因为他是一个更彻底的不含构造函数的抽象类。所以,接口的主要用途就是被实现类实现。一个类可以实现一个接口或多个接口,继承使用extends关键字,而实现则是使用implements关键字。因为一个接口可以继承多个接口,一个类可以实现多个接口,也是Java为单继承灵活性不足所做的补充。

匿名内部类

我们先看这样一段话:人是由大脑、肢体、器官等身体结果组成。而组成我们人体的心脏它也有自己的属性和行为(血液、跳动),显然,此处不能单方面用属性或者方法表示一个心脏了,而需要一个类,但是这个类要依赖于人这个类存在(因为心脏不能脱离人体而存活,当然不考虑现今社会的发达科技,只从正常情况下来说),所心脏以需要写在人类的内部。内部类就相当于其中的某个器官之一。
匿名内部类就是没有名字的内部类;
1、匿名内部类因为没有类名,可知 匿名内部类不能定义构造器
2、因为在创建匿名内部类的时候,会立即创建它的实例,可知匿名内部类不能是抽象类,必须实现接口或抽象父类的所有抽象方法
3、匿名内部类会继承一个父类(有且只有一个)或实现一个接口(有且只有一个),实现父类或接口中所有抽象方法,可以改写父类中的方法,添加自定义方法。
5、当匿名内部类和外部类有同名变量(方法)时,默认访问的是匿名内部类的变量(方法),要访问外部类的变量(方法)则需要加上外部类的类名。

疑问
匿名内部类不能含有static的变量和方法。但是测试发现变量可以被static final修饰,为什么?
主要是因为final类型在编译期间jvm有优化,常量池会维护这些变量。虽然非静态内部类不能脱离外部类这个上下文实例化,但是常量池使得final变量脱离了类实例化这个条件,编译期间便可确定。

总结
1、匿名内部类不能定义任何静态成员、方法。
2、匿名内部类中的方法不能是抽象的;
3、匿名内部类必须实现接口或抽象父类的所有抽象方法。
4、匿名内部类不能定义构造器;
5、匿名内部类访问的外部类成员变量或成员方法必须用static修饰;
6、内部类可以访问外部类私有变量和方法。

05:内部类间的区别

内部类的定义格式如下:
public class 外部类的名称{
//外部类的成员
public class 内部类的名称{
//内部类的成员
}
}
使用内部类有什么好处;
  1. 实现多重继承
  2. 内部类可以很好的实现隐藏:一般的非内部类,是不允许有 private protected权限的,但内部类可以
  3. 减少了类文件编译后的产生的字节码文件的大小
使用内部类的缺点:
  1. 使程序结构不清楚
内部类在编译完成后也会产生.class文件,但文件名称是:外部类名称$内部类名称.class
内部类的种类:
成员内部类、静态内部类、局部内部类、匿名内部类。

一、成员内部类

1、成员内部类也叫实例内部类。应用场合:每一个外部类对象都需要一个内部类的实例,内部类离不开外部类存在(相当于心脏对人体)
2、成员内部类的特征:
作为外部类的一个成员存在,与外部类的属性、方法并列
成员内部类持有外部类的引用
成员内部类中不能定义static变量和方法
3、使用格式:
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
代码演示一:
/*
* 成员内部类
*/public class Body {
String arm;
String leg;
String blood;
public Body(String arm, String leg, String blood) {
super();
this.arm = arm;
this.leg = leg;
this.blood = blood;
}
//内部类Heart
class Heart{
String name;
void work() {
System.out.println("心脏正在给"+arm+leg+"输"+blood);
}
};
}
public class Test {
public static void main(String[] args) {
Body body=new Body("两个胳膊","两条腿","血");
Body.Heart heart=body.new Heart();
heart.work();
}
}
运行截图:
 
代码演示二:
/*
* 成员内部类
*/public class Outer {

private String name="Hello World";
public class Inner{
public void print(){
System.out.println(name);
}
};
public void print(){//定义外部类方法
new Inner().print();//通过内部类的实例化对象调用方法 }
public static void main(String[] args) {
Outer outer=new Outer();
outer.print();//调用外部类的方法 }
}
运行截图:
解释一下,上述代码中,new Inner().print();代码相当于
Inner inner=new Inner();
Inner.print();

 二、静态内部类

1、内部类如果使用static声明,则此内部类就称为静态内部类。(其实也相当于外部类)可以通过外部类 . 内部类来访问。
2、静态内部类使用场合:内部类不需要外部类的实例(注意区分成员内部类),静态内部类存在仅仅为外部类提供服务或者逻辑上属于外部类,且逻辑上可以单独存在。
3、静态内部类的特征:
静态内部类不会持有外部类的引用
静态内部类可以访问外部的静态变量,如果访问外部类的成员变量必须通过外部类的实例访问
4Java中只有内部类才可以是静态的
使用格式:Outer.Inner inner = new Outer.Inner();
代码演示一:
/*
* 静态内部
*/public class Company {
String companyNam;
static String country;
static class Clear{
String name;
public Clear() {
// TODO Auto-generated constructor stub }
public Clear(String name) {
super();
this.name = name;
}

public void work(String name){
String na=new Company().companyNam="联想";
country="中国";
System.out.println(name+"为"+na+"打扫卫生,该公司属于"+country);
}
}
}
public class Test {
public static void main(String[] args) {
Company.Clear zcl=new Company.Clear();
zcl.work("shen_hua");
}
}
运行截图:
代码演示二:
/*
* 静态内部类
*/public class Outer {
private static String info="Hello World";
private int i=8;
static class Inner{
int num=new Outer().i;//获取外部类的非静态成员变量,景天成员变量可以直接使用
public void show() {
System.out.println(info+"---"+num);
}
};
}
public class Test {
public static void main(String[] args) {
Outer.Inner inner=new Outer.Inner();
inner.show();
}
}
运行截图:

三、局部内部类:

1、局部内部类也叫区域内嵌类,局部内部类与成员内部类类似,不过,区域内嵌类是定义在一个方法中的内嵌类。
2、使用场合:如果内部类对象仅仅为外部类的某个方法使用,使用局部内部类
3、特征:
用在方法内部,作用范围仅限于该方法中
根据情况决定持有外部类对象引用
不能使用privateprotectedpublic修饰符
不能包含静态成员
代码演示一:
/*
* 局部内部类
*/public class School {

String schoolName;
String buss="培养人才";
int studentNum;
public School() {
// TODO Auto-generated constructor stub }
public School(String schoolName, String buss, int studentNum) {
super();
this.schoolName = schoolName;
this.buss = buss;
this.studentNum = studentNum;
}

//宣传
public void show(){
final double tvMoney=10000;
final double netMoney=20000;
class AdverTeam{
String teamName="shen_hua";
//电视宣传
public void tvShow(){
System.out.println("宣传队是:"+teamName);
System.out.println("这是电视宣传,学校名称"+schoolName+",业务内容:"+buss+",学校人数:"+studentNum+",宣传所需费用"+tvMoney);
}
//网络宣传
public void netShow(){
System.out.println("宣传队是:"+teamName);
System.out.println("这是网络宣传,学校名称"+schoolName+",业务内容:"+buss+",学校人数:"+studentNum+",宣传所需费用"+netMoney);
}
}
new AdverTeam().tvShow();
new AdverTeam().netShow();
}
}
public class Test {
public static void main(String[] args) {
School qinghua=new School("清华","互联网培训",1000);
qinghua.show();
}
}
运行截图:

四、匿名内部类

1、如果一个内部类在整个操作中只使用一次的话,就可以定义为匿名内部类。匿名内部类也就是没有名字的内部类,这是java为了方便我们编写程序而设计的一个机制,因为有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适。
2、使用场合:简化内部类的使用
3、特征:
使用new创建 ,没有具体位置
创建的匿名类,默认继承或实现new后面的类型
根据使用情况决定是否持有外部类对象引用
内嵌匿名类编译后生成的.class文件的命名方式是”外部类名称$编号.class”,编号为123n,编号为x的文件对应的就是第x个匿名类
代码演示:
/*
* 匿名内部类
*/public interface Person {
public void run();
}
/*
* 测试类
*/public class Test {
public static void main(String[] args) {
Person p=new Person() {
public void run() {
System.out.println("匿名内部类实现的");
}
};
p.run();
}

}
运行截图:

06:重载和重写的区别

方法名
参数列表
参数类型
返回值类型
发生在
绑定时期
重载
相同
不同
不同
无关
一个类
编译期绑定
重写
相同
相同
相同
相同
父子
运行期绑定

07:编译时和运行时的区别

编译时和运行时是软件开发里面用于描述两个不同的软件开发阶段。开发一个程序,程序员首先需要写源代码(Source Code) ,来完成程序的功能。小程序只需要几百行源代码,大程序可能包含成百上千的代码。源代码需要被编译成机器可以识别的程序,这个编译过程被称为编译时。用户可以运行编译过的程序,程序运行的过程被称为运行时。

08:重写,重载,泛型,

分别是在运行时还是编译时执行?

1. 方法重载是在编译时执行的,因为,在编译的时候,如果调用了一个重载的方法,那么编译时必须确定他调用的方法是哪个。如:
当调用evaluate("hello")时候,我们在编译时就可以确定他调用的method #1.
2. 方法的重写 是在运行时进行的。这个也常被称为运行时多态的体现。编译器是没有办法知道它调用的到底是那个方法,相反的,只有在jvm执行过程中,才知晓到底是父子类中的哪个方法被调用了。如下:
试想,当有如下一个接口的时候,我们是无法确定到底是调用父类还是子类的方法
3. 泛型(类型检测) ,这个发生在编译时。编译器会在编译时对泛型类型进行检测,并吧他重写成实际的对象类型(非泛型代码),这样就可以被JVM执行了。这个过程被称为"类型擦除"。
类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。
类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。类型擦除的主要过程如下:
1). 将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。
2). 移除所有的类型参数。

09:静态属性、静态代码块块、非静态属性、

非静态代码块块、构造函数在初始化时的执行顺序

在类new一个对象的过程中,它们的执行顺序如下:
1.实现自身的静态属性和静态代码块。 (注意:它们两个的执行顺序根据自身出现的顺序决定)
2.实现自身的非静态属性和非静态代码块。
3.执行自身的构造函数。
例子:
public class Test{
public static void main(String[] args){
MyClass mc = new MyClass();
}
}
class MyClass{
static String str1 = "MyClass 静态属性";
static{
//静态代码块 类级别
System.out.println(str1);
System.out.println("MyClass  静态代码块");
}
String str2 = "MyClass 非静态属性";
{
//动态代码块   对象级别
System.out.println(str2);
System.out.println("MyClass  动态代码块");


}
public MyClass(){
System.out.println("MyClass  构造方法执行");    
}
}
结果:
MyClass  静态属性
MyClass  静态代码块
MyClass  非静态属性
MyClass  动态代码块
MyClass  构造方法执行
当类被继承时,其子类被new对象的执行过程,初始化顺序如下:
01、初始化父类静态属性
02、执行父类静态代码块
03、初始化子类静态属性
04、执行子类静态代码块
05、初始化父类实例变量
06、执行父类动态代码块
07、执行父类构造方法
08、初始化子类实例变量
09、执行子类动态代码块
10、执行子类构造方法
public class Test{
public static void main(String[] args){
Sub s = new Sub();
}
}
class MyClass{
static String str1 = "MyClass 静态属性";
static{
//静态代码块 类级别
System.out.println(str1);
System.out.println("MyClass  静态代码块");
}
String str2 = "MyClass 非静态属性";
{
//动态代码块   对象级别
System.out.println(str2);
System.out.println("MyClass  动态代码块");
}
public MyClass(){
System.out.println("MyClass  构造方法执行");    
}
}
class Sub extends MyClass{
static String str3 = "sub 静态属性";
static{
//静态代码块 类级别
System.out.println(str3);
System.out.println("sub  静态代码块");
}
String str4 = "sub 非静态属性";
{
//动态代码块   对象级别
System.out.println(str4);
System.out.println("sub  动态代码块");    
}
public Sub(){
System.out.println("sub  构造方法执行");    
}
}

结果:

MyClass  静态属性
MyClass  静态代码块
sub          静态属性
sub          静态代码块
MyClass 非静态属性
MyClass  动态代码块
MyClass  构造方法执行
sub          非静态属性
sub          动态代码块
sub          构造方法执行

10:单例设计模式

解决的问题:保证一个类在内存中的对象唯一性。
比如:多程序读取一个配置文件时,建议配置文件封装成对象。会方便操作其中数据,又要保证多个程序读到的是同一个配置文件对象,就需要该配置文件对象在内存中是唯一的。
Runtime()方法就是单例设计模式进行设计的。
如何保证对象唯一性呢?
思想:
1,不让其他程序创建该类对象。
2,在本类中创建一个本类对象。
3,对外提供方法,让其他程序获取这个对象。
步骤:
1,因为创建对象都需要构造函数初始化,只要将本类中的构造函数私有化,其他程序就无法再创建该类对象;
2,就在类中创建一个本类的对象;
3,定义一个方法,返回该对象,让其他程序可以通过方法就得到本类对象。(作用:可控)
代码体现:
1,私有化构造函数;
2,创建私有并静态的本类对象;
3,定义公有并静态的方法,返回该对象。
---------------------------------------------
//饿汉式
class Single{

//私有化构造函数。
private Single(){

} 

private static Single s = new Single(); //创建私有并静态的本类对象。
public static Single getInstance(){ //定义公有并静态的方法,返回该对象。
return s;
}

}
---------------------------------------------
//懒汉式:延迟加载方式。
 
class Single2{
private Single2(){
}
private static Single2 s = null;
public static Single2 getInstance(){
if(s==null){
s = new Single2();
return s;
}
}

11:23种设计模式

设计模式的分类

总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
其实还有两类:并发型模式和线程池模式。用一个图片来整体描述一下:

详解请看:

12:abstract为什么不能与private,final同时使用?

abstrace是用来修饰类和方法的,被修饰的类和方法必须被子类重写才能实例化,
而private和final修饰的类和方法不能被继承,因此不能同时使用.

13:super和this的异同

this

this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
this的用法在java中大体可以分为3种:

1.普通的直接引用

这种就不用讲了,this相当于是指向当前对象本身。

2.形参与成员名字重名,用this来区分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
    private int age = 10;
    public Person(){
    System.out.println("初始化年龄:"+age);
}
    public int GetAge(int age){
        this.age = age;
        return this.age;
    }
}
 
public class test1 {
    public static void main(String[] args) {
        Person Harry = new Person();
        System.out.println("Harry's age is "+Harry.GetAge(12));
    }
}       
运行结果:
初始化年龄:10
Harry's age is 12
可以看到,这里age是GetAge成员方法的形参,this.age是Person类的成员变量。

3.引用构造函数

这个和super放在一起讲,见下面。

super

super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
super也有三种用法:

1.普通的直接引用

与this类似,super相当于是指向当前对象的父类,这样就可以用super.xxx来引用父类的成员。

2.子类中的成员变量或方法与父类中的成员变量或方法同名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Country {
    String name;
    void value() {
       name = "China";
    }
}
  
class City extends Country {
    String name;
    void value() {
    name = "Shanghai";
    super.value();      //调用父类的方法
    System.out.println(name);
    System.out.println(super.name);
    }
  
    public static void main(String[] args) {
       City c=new City();
       c.value();
       }
}
运行结果:
Shanghai
China
可以看到,这里既调用了父类的方法,也调用了父类的变量。若不调用父类方法value(),只调用父类变量name的话,则父类name值为默认值null

3.引用构造函数

super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Person { 
    public static void prt(String s) { 
       System.out.println(s); 
    
   
    Person() { 
       prt("父类·无参数构造方法: "+"A Person."); 
    }//构造方法(1) 
    
    Person(String name) { 
       prt("父类·含一个参数的构造方法: "+"A person's name is " + name); 
    }//构造方法(2) 
    
public class Chinese extends Person { 
    Chinese() { 
       super(); // 调用父类构造方法(1) 
       prt("子类·调用父类”无参数构造方法“: "+"A chinese coder."); 
    
    
    Chinese(String name) { 
       super(name);// 调用父类具有相同形参的构造方法(2) 
       prt("子类·调用父类”含一个参数的构造方法“: "+"his name is " + name); 
    
    
    Chinese(String name, int age) { 
       this(name);// 调用具有相同形参的构造方法(3) 
       prt("子类:调用子类具有相同形参的构造方法:his age is " + age); 
    
    
    public static void main(String[] args) { 
       Chinese cn = new Chinese(); 
       cn = new Chinese("codersai"); 
       cn = new Chinese("codersai", 18); 
    
}
运行结果:
父类·无参数构造方法: A Person.
子类·调用父类”无参数构造方法“: A chinese coder.
父类·含一个参数的构造方法: A person's name is codersai
子类·调用父类”含一个参数的构造方法“: his name is codersai
父类·含一个参数的构造方法: A person's name is codersai
子类·调用父类”含一个参数的构造方法“: his name is codersai
子类:调用子类具有相同形参的构造方法:his age is 18
从本例可以看到,可以用super和this分别调用父类的构造方法和本类中其他形式的构造方法。
例子中Chinese类第三种构造方法调用的是本类中第二种构造方法,而第二种构造方法是调用父类的,因此也要先调用父类的构造方法,再调用本类中第二种,最后是重写第三种构造方法。

super和this的异同:

  • super(参数):调用基类中的某一个构造函数(应该为构造函数中的第一条语句) 
  • this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
  • super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名    super.成员函数据名(实参)
  • this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
  • 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
  • super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
  • super()和this()均需放在构造方法内第一行。
  • 尽管可以用this调用一个构造器,但却不能调用两个。
  • this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
  • this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
  • 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。

14:成员变量&局部变量&静态变量的区别

成员变量(实例变量)&局部变量区别:

(1)作用域

成员变量:针对整个类有效。
局部变量:只在某个范围内有效。(一般指的就是方法,语句体内)
(2)存储位置
成员变量:随着对象的创建而存在,随着对象的消失而消失,存储在堆内存中。
局部变量:在方法被调用,或者语句被执行的时候存在,存储在栈内存中。
当方法调用完,或者语句结束后,就自动释放。
(3)初始值
成员变量:有默认初始值。
局部变量:没有默认初始值,使用前必须赋值。

成员变量(实例变量)&静态变量(类变量)区别:

A:调用方式
静态变量也称为类变量,可以直接通过类名调用。也可以通过对象名调用。
这个变量属于类。
成员变量也称为实例变量,只能通过对象名调用。这个变量属于对象。
B:存储位置
静态变量存储在方法区长中的静态区。
成员变量存储在堆内存。
C:生命周期
静态变量随着类的加载而存在,随着类的消失而消失。生命周期长。
成员变量随着对象的创建而存在,随着对象的消失而消失。
D:与对象的相关性
静态变量是所有对象共享的数据。
成员变量是每个对象所特有的数据。

作者:Darren

QQ:603026148

以上内容归Darren所有,如果有什么错误或者不足的地方请联系我,希望我们共同进步。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从码农到码到成功

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值