导图社区 java面向对象二
Java基础的后续版本,Java面向对象知识总结,面向对象扩展中...
编辑于2020-07-24 18:39:15Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程
用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。
平和保存和搜索的一些好用的网站,分享一波,好用拿走。
社区模板帮助中心,点此进入>>
Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程
用多线程只有一个目的,那就是更好的利用cpu的资源,因为所有的多线程代码都可以用单线程来实现。说这个话其实只有一半对,因为反应“多角色”的程序代码,最起码每个角色要给他一个线程吧,否则连实际场景都无法模拟,当然也没法说能用单线程来实现:比如最常见的“生产者,消费者模型”。
平和保存和搜索的一些好用的网站,分享一波,好用拿走。
Java面向对象
1. 面向对象概念
1.1. 面向对象思想
面向对象思想: 1.思想:它是一种思想,它能使复杂的问题简单化。角色转变,由执行者转变为指挥者。 2.面向对象是相对于面向过程而言的,它基于面向过程。在面向对象的设计中,将数据和处理数据的方式处理紧密的结合在一起,形成类,在将类进行实例化,就形成了对象。 3.强调:面向对象,对象的属性和方法封装于对象之中,使用属性来描述对象的状态,使用方法处理对象的行为。 面向对象核心:一切皆对象。把程序中的数据和操作都放到对象中进行。 对世界的抽象能力决定开发的难度。
1.2. 与面向过程比较
面向对象和面向过程比较: 1.面向对象是相对面向过程而言,面向对象和面向过程都是一种思想。 2.面向过程:(强调的是功能行为、针对的是数据) 概论:结构化的设计方法,即面向过程。 针对某一需求,自顶向下,逐步细化,将需求通过模块的形式实现,然后对模块中的问题进行结构化编码,可以说是针对需求求解。 弊端:随着软件规模的扩大,需求增加,暴露许多缺点,如软件开发周期长,工程难维护等。 3.面向对象(强调对象) 对象具有属性和方法,在面向对象的设计中,使用属性来描述对象的状态,使用方法处理对象的行为。 将属性和功能封装进对象,强调具备了功能的对象。 4.面向对象是基于面向过程的(C/C++)。 把大象装进冰箱需要几步? 面向过程: 打开,存储,关闭 强调:行为动作功能 打开冰箱 存储进冰箱 关闭冰箱 面向对象: 冰箱、大象--冰箱具有打开存储关闭的属性,大象具有进入的属性 强调:具体的事物(实例、概念) 冰箱.打开。 冰箱.存储。 冰箱.关闭。 *打开和关闭是冰箱的属性
1.3. 类和对象
1.3.1. 类
类的概念: 0、类是构造对象时所依赖的规范,把具有相同特征(属性)和功能、行为(方法)的对象归为一类。 1、类是一个静态的概念,类本身不携带任何数据。当没有为类创建任何对象时,类本身不存在于内存空间中。 2、类是具有相同属性和方法的一组对象集合。 3、类是抽象的概念,仅仅代表事物的模板,它描述一类对象的行为和状态。 4、类是现实世界或思维世界在实体计算机中的反映,它将数据以及这些数据上的操作封装在一起。
1.3.1.1. 修饰符
class 抽象类:abstract 最终类:final 静态类:static 继承:extends 接口:interface 实现:implements public 公共的 private 私有的 protected 受保护的 default 默认的 void 返回值为空 String...
1.3.1.2. 声明-定义(-继承/实现)
定义类: 就是在描述事物,就是在定义某一类事物的属性和行为。属性和行为共同成为类中的成员(成员变量,成员方法)。 声明类: [修饰符] class [extends 父类名] [implements 接口列表] { 成员 } 修饰符:可选,默认 default。用于指定类的访问权限, 可选值: (权限)public,private,protected (功能)abstract和final。 类名:必选,Java 标识符,首字母大写。 extends 父类名:可选,此类继承与哪个类。 implements 接口列表:可选,用于指定该类实现与哪些接口。
1.3.1.3. 类属性和类方法
[修饰符列表] class 类名{ [修饰符] 变量类型 变量=变量值; [修饰符列表] 返回值类型 方法名(){ 方法体 } }
1.3.2. 对象
对象的概念: 1.某一类事物的抽象出来的一个具体实例,通过这个特例处理这类事物出现的问题。 2.每实例化对象都调用一次构造方法,这就是创建对象的过程。 3.对象是一个动态的概念。每一个对象都存在着有别于其它对象的属于自己的独特的属性和行为。 一切事物皆对象 事物:实体、概念 实体:具体实体、数字化实体 概念实体:异常、博客 java 中对对象的操作的实质是对对象的引用的操作: Book book = new Book(); 引用只是存放一个对象的内存地址,并非存放一个对象,严格地说引用和对象是不同的,但是可以将这种区别忽略,如可以简单地说 book 是 Book 类的一个对象,而事实上应该是 book 包含 Book 对象的一个引用。 对象成员: 属性 就是该事物的描述信息(变量) 行为 就是该事物能够做什么(函数/方法)
1.3.2.1. 对象成员
对象成员的调用 成员变量:对象名.变量名; 成员方法:对象名.方法名(..);
1.3.2.2. 实例化对象
1.对象的声明 类名 对象名; //只在内存中建立一个引用,并置初始值null,表示不指向任何内存空间。 //eg:Cat cat; 2.实例化对象 对象名 = new 构造方法名([参数列表]); //为对象分配空间。对象的实例化过程。 格式:类名 对象名 = new 类名(); 3.构造函数实例化对象 类名 对象名 = new 类名(参数1,参数2...);
1.3.3. 类与对象的关系
类是对事物的一个描述,里面封装了具体的属性和方法 对象是类创建的一个实例,可以通过对象来调用类中的属性和方法 类是对象的抽象,对象是类的具体实例。 类映射到java中,描述就是class定义的类。 对象就是具体对应java在堆内存中用new建立实体(实例)。 类属性、类方法:对象共有 --*名称 吃 对象属性、对象方法:对象私有 --*张三 香蕉 *--对象的成员就是对类成员的具体化。
1.4. 三大特性:
1. 封装
封装性: - 1.是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。 - 2.封装的整体规定了不同级别的可见性和访问权限。 封装的好处: - 1.提高代码复用性 - 2.隐藏了具体的实现细节 - 3.对外提供可访问的方式 封装原则: - 1.将不需要对外提供的内容都隐藏起来。 - 2.把属性都隐藏,提供公共方法对其访问。 原因: 之所以对外提供访问方式,就因为可以在访问方式中加入逻辑判断等语句。 对访问的数据进行操作。提高代码健壮性。
2. 继承
继承的概念: > 将多个类中共同的成员变量和成员方法,抽取到另外一个类中(父类),在让多个类去继承这个父类,我们的这个类就可以获取到父类中的成员了。 简言之:抽取多个类共有成员,形成父类,子类拥有父类所有属性和方法。 > Java 语言只支持单一继承,只能继承一个父类,支持多层继承。 聚集分为--has a 聚合:球员是球队中的一员。 组合:组成整体的每一个成员不可或缺。
3. 多态
*抽象类的变量一定指向非抽象类的子类(多态);
4.
1.5. 五大原则:
1.5.1. 单一职责原则
一个类被改变的原因不能超过一个,也就是说,一个类只有一个职责,如果职责过多,代码就会臃肿,可读性更差,也更难以维护
1.5.2. 开放封闭原则
对扩展是开放的,而对修改是封闭的,低耦合高内聚
1.5.3. 里氏替换原则
任何基类可以出现的地方,子类一定可以出现
1.5.4. 依赖倒置原则
程序要依赖于抽象接口,不要依赖于具体实现
1.5.5. 接口隔离原则
一个类对另外一个类的依赖性应当是建立在最小的接口上的
2. 封装性
2.1. 封装
2.1.1. private修饰符
private:私有的。 - 1.权限修饰符: 用于修饰类和类中的成员(成员变量,成员方法)。 - 2.代表私有:只在本类中有效。 将属性私有化以后,类以外即使建立了对象也不能直接访问。但是人应该有年龄,就需要在person类中提供对应访问age的方式。 - 3.注意:私有仅仅是封装的一种表现形式。权限最小--类中隐藏。
2.1.2. ser/get方法
get/set 方法: - set [无返回值] void 有参数列表(类型与参数有关){}(int a,double b,char c...) - get 有返回值(类型与参数有关) 无参数列表{return} 类属性的定义: public class A{ private String name; public void setName(String name){ this.name=name; } public String getName(){ return name; } } public class B{ A a =new A(); a.setName("张三"); sout(a.getName); }
2.1.3. 访问权限
- public :项目中,本类,子类 - protected:同包,本类,子类(同包中的类,一个类创建对象后,可以通过该对象访问自己受保护的变量和方法。) 1.父类的protected成员是包内可见的,并且对子类可见; 2.若子类与父类不在同一包中,那么在子类中,子类实例可以访问其从父类继承而来的protected方法,而不能访问父类实例的protected方法。 3.不同包的非子类不可用。 - default:同包,本类,子类(不同包的子类不可用) - private--本类中有效。通过set额get方法调用、不允许其他的类进行访问 权限顺序: public > default > protected >private 为什么使用 private? 1.拒绝别的类使用,防止别的类修改本类成员 2.提高安全性 3.规范,类中成员变量定义为私有的private
2.1.4. Java常用包
1.Java.lang 此包为基本的包,像 String 这样的类就都保存在此包中,在JDK1.0时如果想编写程序,则必须手工导入此包,但是随后的JDK解决了此问题,所以此包现在为自动导入。 2.Java.lang.reflect 此包为反射机制的包,是 java. lang 的子包,在 Java 反射机制中将使用。 3.Java.util 此包为工具包,一些常用的类库、日期操作等都在此包中,如果把此包精通掌握,则各种设计思路都好理解。 4.Java.text Java 提供的文本处理类库。 5.Java.sql 数据库操作包,提供了各种数据库操作的类和接口 6.Java.net 完成网络编程 7.java.io 输入、输出处理 8.java.awt 包含了构成抽象窗口工具集( abstract window toolkits)的多个类,这些类被用来 构建和管理应用程序的图形用户界面(GUI) 9.java.swing 此包用于建立图形用户界面,此包中的组件相对于 java.awt 包而言是轻量级组件。 10.Java.applet 小应用程序开发包
2.2. 构造函数
2.2.1. 构造函数定义
概念:构造方法是一个与类同名的方法,对象的创建就是通过构造方法完成的。每当类实例化一个对象时,类都会调用构造方法。 是对对象初始化的一种封装,体现封装性。 构造函数的作用: - 1.创建对象。 - 2.给对象(成员)初始化,即为对象成员变量赋初值。 构造函数的特点: - 1.命名必须与类名完全相同 - 2.无返回值(无void) - 3.不能被直接调用 - 4.建类时默认创建构造函数 - 5.多个构造函数以重载方式存在 **注意**: 1.当一个类中没有定义构造函数时,系统会默认给该类加入一个空参数的构造函数。--自定义构造函数时系统就不会再添加。 2.构造函数没有类型。不属于引用类型。 var 引用类型 = new 构造函数(); 什么时候定义构造函数? 已知对象拥有一些属性的时候或对象必须有一些属性时,那么将这些内容定义在构造函数中,需要定义参数。
2.2.2. 构造执行过程
1,new 创建对象,然后传递给构造函数的this 2,在构造函数内部使用对象的动态特性为对象添加成员 Person p=new Person(); 当以new调用构造函数执行时,函数内部会发生以下情况: 1.创建一个空对象 Person p={}; 2.this变量指向对象p Person.call(p) 3.p继承了构造函数Person()的原型 p._proto_=Person.prototype 4.执行构造函数Person()内的代码 内存中构造函数的执行流程: 1.立刻在堆内存中创建一个新的对象 //对象在外部可以实时引用,类似于全局变量 2.将新建的对象设置为函数中的this //this对象为构造函数本身,this后可以添加成员变量 3.逐个/逐行执行函数中的代码 4.将新建的对象作为返回值 //return this self
2.2.3. 与一般函数的区别
构造函数与一般函数的区别: 1.构造函数用来初始化(使用new运算符)一个新建的对象 普通函数不使用 new 运算符的函数 var p=new Person(); var p=Person(); 2.构造函数默认不用return返回值; 普通函数一般都有return返回值。 3.构造函数内部可以使用this关键字来构造属性和方法。 4.构造函数是在对象一建立就运行,给对象初始才化属性,而一般方法是对象调用才执行,给对象添加对象所具备的功能。 5.一个对象的建立,构造函数只运行一次(不能修改值),而一般方法可以被多次调用。 6.构造函数首字母大写;普通函数首字母小写 7.构造函数的函数名与类名相同。
2.2.4. 私有化构造函数
私有化构造方法: 构造方法与其他方法一样,也可以使用private修饰,私有的构造方法无法在本类外部使用,也就导致本类无法用new实例化,这样可以控制对象的生成。 public class Book{ private Book(){}//私有化构造方法 public static Book libraryBorow(){ return new Book(); } public static void main(String[] args){ Book book = Book.libraryBorrow(); } }
2.3. this关键字1
当一个对象创建后,Java 虚拟机(jvm)就会给这个对象分配一个引用自身的指针,这个指针的名字就是 this。 因此,this 只能在类中的非静态方法中使用,静态方法和静态的代码块中绝对不能出现 this,并且 this 只和特定的对象关联,而不和类关联,同一个类的不同对象有不同的 this。 --与对象关联,非静态使用(static属于类,优先于对象创建)。 本质:调用本类属性、调用本类方法(基本/构造)、代表本类对象 this 关键字使用: 1..(构造)方法中指调用该方法的对象; public void setName(String name){ this.name=name; } --this.对象=参数(参数名与对象名相同)---本类功能用到本类对象。 2..this 在构造函数之间相互调用:(首行) 2.1.this()--调用本类中无参构造方法 2.2.this(参数)--调用本类中有参构造方法 *注意匿名类和内部类中的中的 this。 如事件处理。当在匿名类中出现 this 时,这个 this 则指的是匿名类或内部类本身。这时如果我们要使用外部类的方法和变量的话,则应该加上外部类的类名。如下面这个例子: public class C { int i = 1; public C(){ Thread thread = new Thread(){ public void run(){ for(;;){//表示是死循环 C.this.run();//调用外部方法run() try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } };//注意这里有分号; thread.start(); } public void run(){ System.out.println("i = " + i); i++; } public static void main(String[] args) throws Exception { new C(); } }--运行结果:每一秒产生一个数:1,2,3 ……
2.3.1. this关键字2
this 代表的本类的对象。 简单说:哪个对象在调用this所在的函数,this就代表哪个对象。(p在调运setName方法,this代表p对象) A:Person.Class private String name; public void setName(String name){ this.name=name; } public String getName(){ return name; } B.Student.Class Person p=new Person(); p.setName("张三"); System.out.print(p.getName()); --------------------------------------------- new Person();--> p-->setName(name)-->name-->this.name-->getName() ———————————————— 1.调用本类属性、(构造)方法 pubic void people{ String name; int age; // 构造方法 public people(String name,int age){ this.name = name; this.age = age; } // 得到属性 public String getInfo1(){ return "myName:"+this.name+"MyAge:"+this.age; } pulic String toString(String name,int age){ return name+":"+age;} // 得到方法 public String getInfo2(){ return this.toString(); } } public class Demo01 { public static void main(String[] args) throws Exception { People people=new People("小明", 10); System.out.println(people.getInfo1()); System.out.println(people.getInfo2()); } } 2.表示当前对象(相对概念) class People { public void print() { //哪个对象调用了print()方法,this就自动与此对象指向同一块内存地址 System.out.println("this=" + this);//this 就是当前调用对象 } } public class Demo03 { public static void main(String[] args) throws Exception { People people= new People (); People people2= new People (); System.out.println("people=" + people); people.print(); System.out.println("people2=" + people2); people2.print(); } }
2.4. static关键字
static 关键字: 为了节省内存空间,把很多对象共有的数据提取出来--把数据从堆中拿出来放在方法区中。使用目的: 1.脱离对象使用 2.共享数据--对象共享数据。 static 关键字特点: 1.由 static 修饰的变量、常量和方法被称作静态变量、静态常量和静态方法。 2.他们都存放在内存的“静态区”中,这些变量和方法有独立的生存周期。 3.被修饰的成员属于类,不单单是属于某个对象,也就是说可以不靠创建对象来调用。 4.内存中的静态区在整个程序运行结束之后才会释放,所以用静态修饰的代码的生命周期,是整个程序的生命周期。 被修饰成员特点: 1.被对象所共有 2.随着类的加载而加载,优先于对象的加载 3.静态方法只能访问静态成员 4.不能使用super和this,因为其是对象的引用 5.静态成员可以直接被类名调用 6.主函数是静态的 静态成员定义: static 数据类型 变量名; 修饰符 static 返回值类型 方法名(参数列表){//执行语句} 静态成员调用: 类名.静态成员变量名 类名.静态成员方法名(参数) *静态方法可以调用类成员和静态成员,不能调用对象成员,对象成员可以调用静态成员 *静态方法可以通过对象调用非静态方法 什么时候定义静态函数? 1.当功能内部没有访问到非静态数据(对象的特有数据),那么该功能可以定义成静态的。 2.每一个应用程序中都有共性的功能,可以将这些功能进行抽取,独立封装,以便复用。 3.工具类一般都是静态方法 将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象的。 为了更为严谨,强制让该类不能建立对象。可以通过将构造函数私有化完成。
2.5. 匿名对象
什么是匿名对象? 匿名对象是对象的简化形式,直接创建对象,无对象名(载体) new Car(); 调用方式: 1.当对对象方法仅进行一次调用的时. 2.匿名对象可以作为实际参数进行传递 注意:调用属性无意义 使用方式一: 当对对象的方法只调用一次时,可以由匿名对象完成,这样写比较简便,如果对一个对象的多个成员调用,必须给对象起名字 new Car().color()="blue"; 使用方式二: 可以将匿名对象作为实际参数进行传递 实际参数传参方式: main(){ Car c=new Car(); show(c); } public static void show(Car c){ c.num=3; c.color="black"; c.run(); } ----------- 栈:show c-->堆 main c-->堆 堆:new Car() num=4; color="red" 函数 show 对堆内存中数据进行修改 匿名对象作为参数传参: main(){ Car c=new Car(); show(new Car()); } public static void show(Car c){ c.num=3; c.color="black"; c.run(); } ----------- 栈:show c-->堆 main 堆: num=4; color="red" c 对堆内存中数据进行修改
3. 继承性
3.1. 继承的概念
子父类的定义: [修饰符] class 子类名 extends 父类名{子类成员} 继承的优缺点: 优点: 1,实现了代码的复用,提高了程序的可维护性。 2,让类与类之间产生了关系。有了这个关系,才有了多态的特性。因为有继承才有多态。 缺点: 增强了耦合性 (开放的原则:低耦合,高内聚。 耦合:是类与类之间的关系; 内聚:独立完成功能。 ) --------------------------------------------- 注意点: 一、子类的构造方法第一句有默认的super(); 子类会继承父类中的内容 所以在子类初始化时,必须要先到父类中去执行父类的初始化动作,才能更加方便的使用父类当中的内容。 父类的引用,引用父类中的无参构造方法 当父类中没有空参数构造方法时,子类构造方法必须通过显式的super语句来制定要访问的父类中的构造方法 二、super() this() 只能出现在构造方法当中而且只能出现在第一条语句 三、每个类中都会有默认的构造方法,书写格式为 public Name(){ super(); } 四、所有的类都是 Object 的子类。
3.2. 继承后成员特点
1.成员变量 子父类成员变量不重名没有影响 子父类成员变量重名时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字修饰父类成员变量 格式:super.父类成员变量名 2.成员方法 方法重写(override):子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。 重写的应用:子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。 调用父类的成员方法:super.父类成员方法 重写注意事项: (1). 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。 (2). 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。 3.构造方法 (1)构造方法与类名一致,子类无法继承父类的构造方法 (2)构造方法的作用是初始化成员变量的。所以子类的初始化过程中必须先执行父类的初始化动作。子类的构造方法中会默认有一个super(),表示父类的构造方法,父类成员变量初始化后,才可以给子类使用。
3.3. 子类实例化过程
子父类构造方法的执行顺序: 子类的创建需要使用子类的构造函数, 子类构造函数执行的前提就是:父类构造执行结束 【虚拟机保证一个类实例初始化之前,其直接父类或间接父类的初始化过程执行结束】 父类构造调用是将父类可继承的部分初始化成为子类的一部分。 在子类的构造方法的第一行代码如果没有调用父类的构造或者没有调用子类的其他构造,则默认调用父类无参构造. ------------------------------------------ 一个对象实例化过程: Person p = new Person(); 1,JVM 会读取指定的路径下的 Person.class 文件,并加载进内存, 并会先加载 Person 的父类(如果有直接的父类的情况下). 2,在堆内存中的开辟空间,分配地址。 3,并在对象空间中,对对象中的属性进行默认初始化。 4,调用对应的构造函数进行初始化。 5,在构造函数中,第一行会先到调用父类中构造函数进行初始化。 6,父类初始化完毕后,再对子类的属性进行显示初始化。 7,调用构造代码块,进行对象的初始化。 8,继续进行子类构造函数的特定初始化。 9,初始化完毕后,将地址值赋值给引用变量。 ----------------------------------------- 创建对象抽象为该房子: 父工程师先将房子布置一下,子工程师二次布置。 内存抽象:创建对象指令,初始化父类指令(将父类可继承部分初始化,加载入子类内存中),初始化子类指令(加载子类成员)。 ------------------------------------------ 当然:子类的构造函数第一行也可以手动指定 this 语句来访问本类中的构造函数。 子类中至少会有一个构造函数会访问父类中的构造函数。 ----------------------------------------- 子类实例化过程中的注意事项: 1、子类实例化,只会创建一个对象(就是子类对象); 2、子类实例化,会在子类的对象空间中为父类的非静态成员也分配空间; 3、子类构造函数执行时,会通过隐式操作先调用父类构造函数执行; 4、构造函数执行时,哪个类的构造函数,负责为那个类的非静态成员变量显示赋值;
3.4. 抽象类
3.4.1. 抽象类的概念
抽象类:当多个类中出现相同功能,但是功能主体不同,这是可以进行向上抽取构成抽象类,抽象类是针对类而言,类中方法为抽象,不可建立对象,由子类重写其功能后子类建立其子类的对象。只抽取功能定义,而不抽取功能主体。 抽象类的两个特性:强制性、规范性 强制性:子类必须实现,否则子类也定义为抽象类。规范性:所有的子类实现的方法格式是一样的。 abstract:修饰类和方法 抽象类定义格式: abstract class 类名{ [抽象方法] 普通方法--子类可以不重写普通方法 } 抽象类的特点: 1,抽象类中可以有非抽象方法,抽象方法一定在抽象类中。换言之,如果一个类(接口除外)包含抽象方法,那么此类就是抽象类。 2,抽象方法和抽象类都必须被 abstract 关键字修饰。 3,抽象类不可以用 new 创建对象。因为调用抽象方法没意义。 4,抽象类中的方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。 5.抽象类必须有构造,但不能被实例化,不能 new 出对象,作为子类 super 调用.因此,抽象类的变量一定指向非抽象类的子类(多态); *特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。 **不让外界创建对象,现在有几种方式? 1,抽象 --- 父类中使用 2,私有化构造方法--- 工具类中使用. 抽象类的成员特点: 成员变量 可以有成员变量 可以有常量 成员方法 可以有抽象方法 可以有非抽象方法 构造方法 可以有构造方法的,需要对抽象类的成员变量进行初始化;对子类进行实例化。
3.4.2. 抽象方法
抽象方法: 当我们在实现这个方法是无法描述这个方法中的具体内容,就定义这个方法为抽象方法。使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。 抽象方法的定义: abstract 方法名(参数列表); 抽象方法的使用: 在父类中只对函数进行声明,不定义函数体,由子类对父类的抽象方法进行重写。
3.4.3. 抽象类与一般类的区别
抽象类与一般类的区别: 相同: 都是一个类,用来描述一个事物 里面都可以定义属性与方法。 不同: ① 一般类:描述一个具体的事务。 抽象类:描述的是抽象(不具体)的事务. ② 抽象类中可以定义抽象方法。 一般类中不可以定义抽象方法。 ③ 一般类是可以实例化(创建对象)。 抽象类不可以实例化。 抽象关键字 abstract 和我们所学过的哪些关键字不可以共存: final 类不可以被继承,不能被重写 abstract--必须重写才能使用 private 只能本类使用,abstract 需要继承 static 不需要实例化用类名调用,abstract 不能被实例化-抽象方法无方法体,调用无意义
3.5. 方法重写
重写的特点: 1.首先要有继承, 2.子类中的方法与父类中的方法方法名和参数列表,返回值都相同 3.发生在子类与父类之间,重新定义子类中的该函数的功能 重载:overload 方法名相同,参数列表不同(个数、类型)与返回值无关。发生在同类之中。 重写:override 方法名相同,定义(方法名,参数列表,返回值)都相同,函数功能不同。发生在子父类之中。
3.6. super关键字
super的使用: 1.直接引用父类的实例变量 super.color 2.通过super 来调用父类方法 super.eat() 3.使用super来调用父类的构造函数 super和this 父类空间优先于子类对象创建 4.子类的构造方法重构时,要先调用对应的父类的构造方法(如果有),super(参数对应)放在第一行。 如果父类没有重构构造方法,子类重构时会调用父类的默认的构造方法。父类多个构造函数,子类 super 任一。 public Children(String s,int i) { super(s,i); }
3.6.1. super和this调用
super 和 this 的异同: 1.子类要访问父类中的同名变量用super,如果子类中出现非静态的同名成员变量时,子类要访问本类中的变量,用 this。 2.super:代表父类的存储空间的标识(父类的引用) this:代表当前对象的引用(谁调用就代表谁) 3.当子类调用的属性方法在子类中不存在时,那么 this 和 super 都是调用父类的属性或者方法(非私有)。 4.都必须放在函数中的第一位,且不能同时使用 ------------------------------------------- java 中关于 this 和 super 的调用问题: public class Person(){ private String name; private int id; public Person(){ System.out.println("Person()"); name="zhangshan"; age="25"; } public Person(String name,int age){ //super();//Object System.out.println("Person(String,int)");//3 setName(name);//4 setAge(age);//5 } 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; } } public class Student extends Person{ private int id; public int getId(){return id;} public void setId(int id){this.id=id;} public Student(){ this(7,"admin",30);//1 System.out.println("Student()");//8 } public Student(int id,String name,int age){ super(name,age);//2 System.out.println("Student(int,String,int)");//6 this.setId(id);//7 } public static void main(Strign[] args){ new Student(); } }
3.7. 接口
3.7.1. 接口的定义
接口:interface--实现: implements 定义格式:(接口是特殊的抽象类) [修饰符] interface 接口名[extends 父接口列表]{ [public] [static] [final] 常量; [public] [abstract] 方法; } 接口的特点: 1.类的“多继承”通过接口实现 2.接口不能创建对象:存在抽象方法,为抽象类不能创建对象。 3.接口不是类。声明时使用的为 interface 关键字,但是编译后仍然会产生 .class 文件。 4.接口为什么不能实例化: 概念/理解:事务与事务之间的联系,不存在实际的事物。 接口中的成员特点: 1.成员固定 1.1.公共的静态常量(public final static ) 1.2.公共的抽象方法(public abstract ) 1.3.静态内部类(static class) 2.接口中修饰符固定:(直接定义成员 默认会加上应用关键字) 成员常量:public static final (必须赋值) 成员函数:public [static] abstract void Demo(){};--只能是静态的--不能实例化,只能被类名调用 接口的成员都是 public 3.构造方法:接口中是没有构造方法的. 接口的好处: 1.提高了扩展性,扩展功能 2.规定了规则 3.降低了耦合性(事物之间的紧密程度)
3.7.2. 接口和类的关系
接口和类的关系: 接口是对外暴露的规则,是程序的功能扩展,可以用来多实现。 A:类与类之间: 继承关系,一个类只能直接继承一个父类,但是支持多重继承。 B:类与接口之间: 实现关系,一个类可以实现多个接口。 C:接口与接口之间: 只有继承关系,一个接口可以继承多个接口 D:接口不是类。
3.7.3. 接口和抽象类的区别
接口和抽象类的区别: 1.共性: 不断的进行抽取,抽取出抽象的,没有具体实现的方法,都不能实例化(不能创建对象)。 2.区别: 区别1:与类的关系 类与接口是实现关系,而且是多实现(多个叔叔)。 类与抽象类是继承关系,Java 中的继承是单一继承,可以多层继承,一个类只能继承一个父类,但是可以有爷爷类。 区别2:成员 a. 成员变量 抽象类可以有成员变量,也可以有变量。 接口只能有常量,默认修饰符 public static final b. 成员方法 抽象类可以有抽象方法,也可以有非抽象方法(静态方法) 接口只能有抽象方法,默认修饰符 public [abstract] c. 构造方法 抽象类有构造方法,为子类提供(子类创建对象)。 d. 接口没有构造方法,不能被继承,只能实现接口。抽象类可以实现接口。 E. 设计模式。抽象类:模板设计模式。接口:工厂设计模式、代理设计模式 *子类若不全部实现接口中的方法子类就是一个抽象类。 抽象类和接口的对象都是利用对象多态性 的向上转型,进行接口或实例化操作。 接口和抽象类都可以使用时优先考虑接口。
3.7.4. 接口的实现
实现的关键字:implements 实现的语法: [修饰符] class [extends 父类名] [implements 接口1,接口2...] { 接口实现; } 接口:是不可以创建对象的,因为有抽象方法。 需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。 否则子类是一个抽象类。
3.8. final关键字
final 关键字特点:最终化 1.final可以修饰类,类成员(方法,属性),变量。 2.final修饰的类不可以被继承。为了避免被继承,被子类复写功能。 3.final修饰的方法可以被继承,不可以被重写。变量名全部大写。 4.final修饰的变量是一个常量。只能被赋值一次。 5.内部类只能访问被final修饰的局部变量。 final 的属性可以赋值的位置: 1.声明的同时赋值。 2.在构造中赋值,但必须保证所有的构造都赋值 3.可以在语句块中赋值。 final 修饰的变量为常量: 常量的书写规范所有字母都大写,如果由多个单词组成。 单词间通过_连接。 final 不能与那些关键词同时使用: set:方法在构造时是不执行的。 abstract:构造函数必须被继承。
4. 多态性
4.1. 特点
4.1.1. 多态特点
多态的概念: 多态是面向对象程序设计的又一个重要特征,是允许程序中出现重名现象。多态的特性使程序的抽象程度和简捷程度更高,有助于程序设计人员对程序的分组协同开发. Java 语言中含有方法重载与对象多态两种形式的多态。 简言之:多态:一种事物的多种形态。例如猫属于猫类型,也属于动物类型。 ·动物是猫这种具体事物中抽取出来的父类型。 ·多态就是把父类型引用指向了子类对象。 父类类型 变量名 = new 子类类型(); 多态的前提:继承、封装。 多态的特点:一个东西的多种形态。 多态在面向对象中的内容: 1.方法重载:在一个类中,允许多个方法使用同一个名字,但方法的参数不同,完成的功能也不同。 2.对象多态:子类对象可以与父类对象进行相互的转换,而且根据其使用的子类的不同完成的功能也不同。 3.数据类型的多态:byte short int long、float double 4.数据类型的封装(装箱、拆箱):int integer、float Float 5.抽象类(接口)的变量一定指向非抽象类的子类。 多态的优缺点: 弊端: 通过父类引用操作子类对象,只能使用父类中已有的方法,不能直接使用子类中特有的方法。 优点: 可以提高可维护性(多态前提所保证的),提高代码的可扩展性,提高了程序的拓展性。 多态总结为: 一、使用父类类型的引用指向子类的对象; 二、父类引用只能调用父类中定义的方法和变量; 三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用) 四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。
4.1.2. 多态成员特点
多态成员特点: 简单记: 成员变量 编译时看的是左边,运行时看的左边 成员方法 编译时看的是左边,运行时看右边 静态方法 编译时看的是左边,运行时看的也是左边 设计时多态:即重载,是指 Java 允许方法名相同而参数列表不同(返回值可以相同也可以不相同)。 运行时多态:即重写,是指 Java 运行根据调用该方法的类型决定调用哪个方法。(方法名、参数列表和返回值类型都相同)
4.2. 向上转型/向下转型
多态中向上转型与向下转型: 向上转型:自动类型提升 向下转型:强制类型转换 多态的转型分为向上转型与向下转型两种: A:向上转型:当有子类对象赋值给一个父类引用时,便是向上转型,多态本身就是向上转型的过程。(编译时) 使用格式: 父类类型 变量名 = new 子类类型();//类型提升 如:Animal animal = new Cat(); B:向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用转为子类引用,这个过程是向下转型。(运行时)向下转型,如果是直接创建父类对象,是无法向下转型的。 使用格式: 子类类型 变量名 = (子类类型) 父类类型的变量; 如:Cat cat = (Cat) animal;
4.3. instanceof 关键字
instanceof--判断变量的数据类型 多态在未知继承关系时强制转换之前要用 instanceof 做判断,防止出错。 在多态中成员函数的特点: 在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。 在运行时期:参阅对象所属的类中是否有调用的方法。 简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。 在多态中,成员变量的特点: 无论编译和运行,都参考左边(引用型变量所属的类)。 instanceof 也支持父类的类型,如果是判断父类类型,也返回true。
5. 异常体系
5.1. 异常的概念
异常:就是程序在运行时出现不正常情况。 面向对象:异常问题也是现实生活中一个具体的事物,也可以通过 java 的类的形式进行描述。并封装成对象。其实就是 java 对不正常情况进行描述后的对象体现。 好处: 1,将问题进行封装。 2,将正常流程代码和问题处理代码相分离,方便于阅读。
5.2. 异常的体系
Throwable:可抛出/异常(可抛性) 两种:一种是严重的问题,一种非严重的问题。 1·Error(系统错误)(错误) 通常出现重大问题如:运行的类不存在或者内存溢出等, 不编写针对代码对其处理,让程序停止,需要对代码进行修正。 2·Exception(编译检查/时异常)(异常) 该异常在编译时,如果没有处理(没有抛也没有 try),编译失败。该异常被标识,代表这可以被处理。可以通过 try catch finally 处理。 --RuntimeException(运行时异常) --IOException *Exception 和 Error 的子类名都是以父类名作为后缀。 异常体系的特点: 1.异常体系中的所有类以及建立的对象都具备可抛性,也就是说可以被 throw 和 throws 关键字所操作.只有异常体系具备这个持点。 2.异常类可以声明多个,用逗号分割。 3.声明异常时,建议声明更为具体的异常。这样处理的可以更具体,不要定义多余的 catch 块。 4.对方声明几个异常,就对应有几个 catch 块,如果多个 catch 块中的异常出现继承关系,父类异常 catch 块放在最下面。 异常在进行 catch 处理时,catch 中一定要定义具体处理方式。不要简单定义一句 e.printstackrrace()。也不要简单的就书写一条输出语句。 String (e.)getMessage:()获取异常信息。
5.2.1. 捕获异常 try
捕捉的三种方式: try{ 执行可能产生异常的代码; [异常代码/throw 异常对象/throws 异常类] }catch(异常类 exception 变量 e) { [已经]处理异常的代码; }finally { 一定会执行的代语句; } 有三种格式: 1.try{} catch(){} 2.try{} finally{} 3.try{} catch(){} finally{} 注意: 1.finally中定义的通常是关闭资源代码。因为资源必须释放。 2,finally 只有一种情况不会执行。当执行到 system.exit();
5.2.2. 抛出异常 throw
throw 抛出异常: 语法:throw new 异常类名(参数); throw 使用: 1.用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。 2.也可以用在代码块中,但如果代码块中抛出的异常对象是由检查时异常创建的,则必须使用 try-catch 进行处理。 int a=0; { if(b==0){ try{ throws new Exception(分母不能为0); }catch(Exception e){ e.printStackTrace(); } } } --如果替换成 new RuntimeException(“操作失败:分母不能为0”),则可以省去 try-catch 语句块。 3.throw 对象将异常抛给谁 3.1抛出给自己 3.2抛出给方法调用者
5.2.3. 声明异常 throws
声明对象: throws 异常的处理方式:声明方法可能要抛出的各种异常,使用 throws 关键字声明的方法表示此方法不处理异常,而交给方法调用处进行处理。 throws 语法: []([]) [throws] throw 与 throws 的区别: 1.抛出的东西不同:throw 是(语句)抛出一个异常,抛出的是具体的异常对象,而 throws 是(方法)抛出一个异常,抛出的是抽象的异常类; 2.使用位置不同:throw 一般用在方法体中,也可用在代码块中,但是如果抛出的是检查时异常类创建的对象,则必须使用 try-catch 自行处理;throws 只能用在方法声明括号后面; ---------------------------------------------- import java.util.Scanner; public class 异常测试 { public static double yichang() throws Exception { //在方法名的后面加throws Exception,声明即便出错了也继续执行,由调用这个方法的函数来try System.out.println("请输入一个非零数字"); Scanner sc=new Scanner(System.in); String a=sc.nextLine(); int shu=Integer.parseInt(a); double jg=100/shu; return jg; } public static void main(String[] args) { try{ double c=yichang(); //调用方法,如果没有异常,直接输出,如果有异常则走catch System.out.println(c); } catch(Exception e){ System.out.println("输入不正确"); } } }
5.3. 异常注意事项
异常处理原则: 1.处理方式有两种:try 或者 throws。 2.调用到抛出异常的功能时,抛出几个,就处理几个。一个try对应多个catch. 3.多个catch,父类的catch放到最下面。 4.catch内,需要定义针对性的处理方式,不要简单的定义printStackTrace(输出异常信息),输出语句。也不要不写。 当捕获到的异常,本功能处理不了时,可以继续在catch中抛出 try { throw new AException(); } catch (AException e){ throw e; } 如果该异常处理不了,但并不属于该功能出现的异常。可以将异常转换后,再抛出和该功能相关的异常。或者异常可以处理,当需要将异常产生后的和本功能相关的问题提供出去,让调用者知道。并处理。也可以将捕获异常处理后,转换新的异常。 try { throw new AException(); }catch(AException e) { //对AException处理。 throw new BException(); } 抛出异常的三种情况: 1.系统自动抛出:当程序出现一些逻辑错误、转换错误时,系统会自动抛出异常。 --查看系统抛出异常: 2.throws用来标明一个成员函数可能抛出的各种“异常”,然后交给上层调用它的方法程序处理。出现在方法头,谁调用,谁处理。 3.throw 语句用来明确地抛出一个“异常”。出现在方法体。 在子父类覆盖中的体现: 1.父类存在异常时,子类只能抛出父类的异常或者父类异常的子异常,子类的新异常,只能 try,不能抛。 2,如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。 3,如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法发生了异常。就必须要进行 try 处理。绝对不能抛。 *定义变量要在 try 之前
5.4. 常见的异常
Throwable: Error: 虚拟机错误:VirtualMachineError 内存溢出:OutOfMemoryError 线程死锁:ThreadDeath Exception: 输入输出(I/O)异常:IOException SQL异常:SQLException 运行时异常:RuntimeException: NullPointerException 空指针异常, ArrayIndexOutOfBoundsException 数组下标越界异常, NegativeArrayException 数组负下标异常, ClassCaseException 类型转换异常, NumberFormatException 字符串转换为数字异常: ArithmaticException 算数异常 如除数为零, IllegalArgumentException 参数不合法异常 , 文件未找到异常:FileNotFoundException 违背安全原则异常:SecturityException 文件已结束异常:EOFException 方法未找到异常:NoSuchMethodException
5.5. 自定义异常
自定义异常概念: 因为项目中会出现特有的问题,而这些问题并未被 java 所描述并封装对象。所以对于这些特有的问题可以按照 java 的对问题封装的思想。将特有的问题。进行自定义的异常封装。 说明: 1.所有异常都必须是 Throwable 的子类。 2.如果希望写一个检查性异常类,则需要继承 Exception 类。 3.如果你想写一个运行时异常类,那么需要继承 RuntimeException 类。 原因: 1,为了让该自定义类具备可抛性。 2,让该类具备操作异常的共性方法。 3,重写方法:构造方法; 当要定义自定义异常的信息时,可以使用父类已经定义好的功能。一般定义更多的参数,不使用父类定义的异常格式。 异常信息传递给父类的构造函数。 自定义异常:按照java的面向对象思想,将程序中出现的特有问题进行封装。 --------------------------------------------- 自定义异常: class IllegalAgeException extends Exception { //默认构造器 public IllegalAgeException() { } //带有详细信息的构造器,信息存储在message中 public IllegalAgeException(String message) { super(message); } } 使用: class Person { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) throws IllegalAgeException { if (age throw new IllegalAgeException("人的年龄不应该为负数"); } this.age = age; } public String toString() { return "name is " + name + " and age is " + age; } } public class TestMyException { public static void main(String[] args) { Person p = new Person(); try { p.setName("Lincoln"); p.setAge(-1); } catch (IllegalAgeException e) { e.printStackTrace(); System.exit(-1); } System.out.println(p); } } 使用异常机制的建议: 1.要避免使用异常处理代替错误处理,这样会降低程序的清晰性,并且效率低下。 2.处理异常不可以代替简单测试---只在异常情况下使用异常机制。 3.不要进行小力度的异常处理---应该将整个任务包装在一个try语句块中。 4.异常往往在高层处理(先了解!后面做项目会说!) 。
6. 代码块
代码块的指向顺序: 划分就是为了更好的确定和细致化功能,以方便使用。 代码块的执行顺序(不包括同步代码块) 没有继承: 1. 静态成员变量 2. 静态代码块 3. 普通成员变量 4. 普通代码块 5. 构造代码块 6. 构造函数 总结: 1. 静态->普通 2. 变量->代码块->构造函数 3. 构造函数是最后执行的 子父类之间: 1. 父类的静态成员变量 2. 父类的静态代码块 3. 子类的静态成员变量 4. 子类的静态代码块 5. 父类的成员变量 6. 父类的代码块 7. 父类的构造函数 8. 子类的成员变量 9. 子类的代码块 10. 子类的构造函数 总结: 1. 先父类再子类 2. 如果子类有静态成员变量和静态代码块,则执行完父类的静态成员变量和静态代码块后,接着执行子类的静态变量和静态代码块,否则直接按照父类的变量->代码块->构造函数,再执行子类的变量->代码块->构造函数 3. 需要注意的是子类的静态变量和静态代码块是优先于父类的普通成员变量和代码块以及构造函数的。 4. 先静态->再普通
6.1. 局部代码块
局部代码块: 位置:在方法内部 作用:是用来限制变量的声明周期 以”{}”划定的代码区域,此时只需要关注作用域的不同即可。 方法和类都是以代码块的方式划定边界的
6.2. 静态代码块
静态代码块: 它优先于主方法执行、优先于构造代码块执行,当以任意形式第一次使用到该类时执行。 该类不管创建多少对象,静态代码块只执行一次。 可用于给静态变量赋值,用来给类进行初始化。 静态代码块格式: static{ 静态代码块中的执行语句。 }
6.3. 同步代码块
同步代码块(被synchronized修饰的代码块 ) (1)synchronized同步方法 ①对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态。 ②同一时间只有一个线程可以执行synchronized同步方法中的代码 (2)synchronized(this)同步代码块 ①对其他synchronized同步方法或synchronized(this)同步代码块呈阻塞状态。 ②同一时间只有一个线程可以执行synchronized(this)同步代码块中的代码。
6.4. 构造代码块
构造代码块的作用: 1.给对象进行初始化。(定义不同对象的共性初始化方式。) 2.对象一建立就运行,而且优先于构造函数执行。每个对象都执行。 3.直接在类中方法外定义且没有加static关键字的代码块称为{}构造代码块。 和构造函数的区别: 构造代码块是给所有对象进行统一初始化,而构造函数是给对应的对象初始化。 package test; public class CodeBlock { { System.out.println("第一代码块"); } public CodeBlock() { System.out.println("构造方法"); } { System.out.println("第二代码块"); } public static void main(String[] args) { new CodeBlock(); new CodeBlock(); new CodeBlock(); } } --------------------------- 运行结果: 第一代码块 第二代码块 构造方法 第一代码块 第二代码块 构造方法 第一代码块 第二代码块 构造方法
7. 各种方法的特点
一般方法、静态方法、构造函数、抽象方法的区别: (修饰符、命名、生命周期、调用方式) 一般方法:成员方法 1.权限名 返回值 方法名(参数列表){方法体 return } 2.调用方式--对象名.方法名 对象建立之后由对象调用,用来给对象添加功能,可以调用多次。 3.首字母小写。 4.可以调用静态成员和对象成员 静态方法:类方法 1.权限名 static 返回值 方法名(参数列表){方法体 return } 2.调用方式--类名.静态方法名 3.静态方法中没有构造函数,也不可以使用 this 和 super。 构造函数:对象初始化 1.函数名与类名相同,无返回值,多个构造函数之间以重构方式存在 2.对象一建立就运行,用来给对象初始化,一个对象只调用一次,只有构造函数才能创建对象。 3.首字母大写。 抽象方法:父类方法 1.abstract 修饰类成员方法。 2.---类中有抽象方法,就必须定义类为抽象类 3.---必须被继承,子类中必须重写父类中的所有抽象方法,否则子类也是构造函数 4.---抽象类不可以实例化,因为调用抽象方法无意义-其中必定有构造函数(被继承)
7.1. 普通方法
7.2. 静态方法
7.3. 构造函数
7.4. 抽象方法
8. 各种属性的区别
静态变量与成员(全局)变量的区别: 1.使用-加载方式、时间 静态变量:随着类的加载而加载 成员变量:对象创建之后由对象使用 2.调用-方式 静态变量:可以被对象调用,建议使用类名调用 成员变量:只能被对象调用 3.内存中的位置 静态变量:存储在方法区之中 成员变量:存储在堆内存之中 注意: 1.静态方法可以访问非静态成员吗? 不可以,静态方法是随着类的加载而加载,这是可能还未创建该类的对象 所以非静态成员还未加载到内存之中。 2.非静态方法可以访问静态成员吗? 可以,非静态方法加载晚于静态变量。 成员(全局)变量与局部变量的区别: 1.定义位置不同 成员变量定义在类中--整个类中都可以被访问 局部变量定义在方法中--局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。 2.内存中的位置不同 成员变量:在堆内存中 局部变量:在栈内存中 3.生命周期不同 成员变量,随着对象的加载而使用。随着对象的消失而消失, 局部变量,随着函数/方法的创建而使用 4.初始化不同 成员变量默认初始化值--堆 局部变量自己定义初始化值--栈
8.1. 局部变量
8.2. 全局
8.2.1. 成员变量
8.2.2. 静态变量
9. 内部类
内部类的概念: 将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。内部类分为: 成员内部类/局部内部类/静态内部类/匿名内部类。 内部类特点: 1.内部类依靠外部类而存在,即在创建一个普通内部类对象时首先需要创建其外部类对象。 2.内部类可以直接访问外部类中的成员,包括私有成员。而外部类要访问内部类中的成员必须要建立内部类的对象。 格式: class outer{ class inner{ } } 何时使用内部类? 使用:当描述事物时,事物的内部还有事物,该事物用内部类来描述。 因为内部事务在使用外部事物的内容。 (组合对象)
9.1. 成员内部类
成员内部类:内部类定义在外部类的成员位置时。 成员内部类的特点: 1.当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。 格式:外部类名.内部类名 变量名= new 外部类().内部类(); Outer. Inner in=new Outer(). new Inner(); 2.当内部类在外部类的成员位置上,就可以被成员修饰符所修饰。比如, private:将内部类在外部类中进行封装。 static;内部类就具备 static 的特性。 当内部类被 static 修饰后,只能直接访问外部类中的 static 成员,出现了访问局限。 在外部其他类中,如何直接访问 static 内部类的非静态成员呢? new Outer.Inner().function(); 注意:当内部类中定义了静态成员,该内部类必须是 static 的。 当外部类中的静态方法访问内部类时,内部类也必须是 static 的。 -------------------------------------------- class Circle { private double radius = 0; public static int count =1; public Circle(double radius) { this.radius = radius; } class Draw { //成员内部类 public void drawSahpe() { System.out.println(radius); //外部类的private成员 System.out.println(count); //外部类的静态成员 } } } 成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)。 -**当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问: 外部类.this.成员变量 外部类.this.成员方法
9.2. 局部内部类
局部内部类:内部类定义在局部时(方法体内)。 局部内部类的特点: 1,不可以被成员修饰符修饰。 2,可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量。只能访问被 final 修饰的局部变量。 3.局部内部类可以使用final修饰,普通的内部类不行。 4.定义在方法或构造中。 ------------------------------------------ class People{} class Man{ public People getWoman(){ class Woman extends People{ //局部内部类 int age =30; } return new Woman(); } }
9.3. 静态内部类
静态内部类: 静态内部类和静态变量类似,使用static修饰。静态内部类可以在不创建类的情况下直接使用。普通的类不能使用static修饰,只有内部类可以。 静态内部类和非静态内部类的区别: 一、非静态内部类: 1、变量和方法不能声明为静态的。(类的编译顺序:外部类--静态方法或属性--内部类) 2、实例化的时候需要依附在外部类上面。比如:B是A的非静态内部类,实例化B,则:A.B b = new A().new B(); 3、内部类可以引用外部类的静态或者非静态属性或者方法。 二、静态内部类: 1、属性和方法可以声明为静态的或者非静态的。 2、实例化静态内部类:比如:B是A的静态内部类,A.B b = new A.B(); 3、内部类只能引用外部类的静态的属性或者方法。 4、如果属性或者方法声明为静态的,那么可以直接通过类名直接使用。比如B是A的静态内部类,b()是B中的一个静态属性,则可以:A.B.b(); -------------------------------------------- public class Test { public static void main(String[] args) { Outter.Inner inner = new Outter.Inner(); } } class Outter { static class Inner { } }
9.4. 匿名内部类
匿名内部类 :是内部类的简化写法。它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象。开发中,最常用到的内部类就是匿名内部类了。 1.匿名内部类没有类名,其他的成员都具备。 2.(前提)匿名内部类必须继承一个父类或实现一个接口 3.其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。可以理解为带内容的对象。 4.没有类名的内部类,一般用于接口的实现。只能被使用一次。 5.格式: new 父类/接口名(){ 实现父类/接口的方法; } --------------------------------------------- public class InnerDemo3 { public static void main(String[] args) { showFly( new FlyAble(){ public void fly() { System.out.println("我飞了~"); } }); } public static void showFly(FlyAble f) { f.fly(); } }
10. 主方法
主函数-java 程序的入口 public static void main(string[]args){ 类成员 } --String[]args:命令行参数。主方法的形参为数组,其中args[0]`args[n]分别代表程序的第一个参数到第n个参数,可以使用args.length获取参数个数。 主函数:是一个特殊的函数。作为程序的入口,可以被jvm调用。 主函数的定义: public:代表着该函数访问权限是最大的。 static:代表主函数随着类的加载就已经存在了。 void:主函数没有具体的返回值。 main:不是关键字,但是是一个特殊的单词,可以被jvm识别。 (string[] args):函数的参数,参数类型是一个数组,该数组中的元素是字符串,字符串类型的数组。 主函数是固定格式的:jvm识别。 arguments 参数-可以替换-其他必须固定 jvm在调用主函数时,传入的是new string[0]; system.out.println(args[x]);
11. 单例设计模式
什么是设计模式: 设计模式:最优化 解决方案--复杂化-框架 Java中有23中设计模式 单例设计模式:解决一个类只存在一个对象的问题,保证对象唯一。 单例设计模式: 1,为了避免其他程序过多建立该类对象。先禁止其他程序建立该类对象。 2,还为了让其他程序可以访问到该类对象,只好在本类中,自定义一个对象。 3,为了方便其他程序对自定义对象的访问,可以对外提供一些访问方式。 这三部怎么用代码体现呢? 1,将构造函数私有化。 2,在类中创建一个本类对象。 3,提供一个方法可以获取到该对象。 4, static 静态化实例 5, final 最终化实例 -------------------------------------------- 实现: class Singleton{//定义一个类 private Singleton(){}//构造方法私有化 private final static Singleton instance = new Singleton();//私有、静态、唯一对象 public void print(){ System.out.printin("Hello World."); } public static Singleton getlnstance(){//取得本类对象 return instance; } public class TestDemo{ public static void main(String args[]){ Singleton inst=null;//声明对象 inst=new Singleton.getlnstance();//利用“类.static方法()”方式取得实例化对象 inst.print();//调用方法 } }--HelloWorld
11.1. 饿汉式
饿汉式:--先加载再使用 class single { private single(){} private static singles = new single(); public static single getInstance(){ return s; } } class singleDemo{ public static void main(string[] args){ single ss=single.getInstance(); } }
11.2. 懒汉式
懒汉式:--需要时再就加载 class Single { private Single(){} private static singles=null; public static single getInstance(){ if(singles==null){ singles=new Single(); return singles; } } class singleDemo{ public static void main(string[] args){ single ss=single.getInstance(); } } 懒汉式延时加载,多线程会出现安全隐患 加同步可以解决,会低效,用双层锁可以解决效率问题,锁是该类所属的字节码文件对象