面向对象的内容框架
1.类和类的成员:属性、方法、构造器、代码块、内部类
2.面向对象的三大特征:封装性、继承性、多态性
3.其他关键字:this、super、static、abstract、interface、import等
什么是面向对象?
面向过程(POP)与面向对象(OOP)
两者都是一种思想,面向对象是相对于过程而言的。
面向过程,强调的是功能行为,以函数为最小单位,考虑怎么做。
面向对象,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
类和类的成员
类(class)和对象(Object):
类:对一类事物的描述,是抽象的、概念上的定义
对象:是实际存在的该类事物的每个个体,因而也成为实例(instance)
属性 = 成员变量 = field = 域、字段
方法 = 成员方法 = 函数 = method
Java内存解析
内存解析:
类装载器(class文件)
内存区域:方法区(Method Area) 、 虚拟机栈(VM Stack) 、 本地方法栈(Native Method Stack) 、堆(Heap)、程序计数器(Program Couter Register)、垃圾收集器
执行引擎、本地库接口、本地方法库。
堆:此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
栈:是指虚拟机栈。虚拟机栈用于存储局部变量等。
方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
属性
局部变量与属性的对比:
属性(成员变量) vs 局部变量
1.相同点;
①定义变量的格式相同
②先声明后使用
③变量都有其对应的作用域
2.不同点:
①在类中声明的位置不同:
属性:直接定义在类的{}内
局部变量:声明在方法内、方法形参、代码块内、构造器内部的变量。
②关于权限修饰符:
属性:可以在声明属性时,指明其权限,使用权限修饰符
常用的权限修饰符:private、public、缺省、protected
局部变量:不可以使用权限修饰符
③默认初始化值的情况
属性:类的属性,根据其类型都有默认初始化值。
整型(byte\short\int\long),0
浮点型(float\double),0.0
字符型(char),0(或'\u0000')
布尔型(boolean),false
引用数据类型(类、数组、接口),null
局部变量:没有默认初始化值。
意味着,我们在调用局部变量之前必须赋值。
特别的,形参我们在调用的时候赋值就可以。
④在内存中加载的位置
属性:加载到对空间中(非static)
局部变量:加载到栈空间中。
万事万物皆对象
/*
万事万物皆对象:
1.java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构。
2.涉及到Java语言与前端Html、后端的数据库交互时,前后端的机构在Java层面交互时,都体现为类、对象。
方法
类中的方法的声明和使用:
方法:描述类应该具有的功能。
比如:Math类:sqrt()\random()\...
Scanner类:nextXxxx()...
说明:
权限修饰符:
1.Java规定的4中权限修饰符:public \protected\ private\缺省
2.返回值类型:有返回值 vs 没有返回值
① 如果有返回值,则必须在方法声明时,必须指定返回值类型。同时,在方法中,需要使用return返回。
② 如果没有返回值,则方法声明时,使用viod来表示。
3.方法名:属于标识符,要遵循规律。见名识意。
4.形参列表:方法可以声明0个,1个,或多个。
5.方法体:方法功能的体现。
方法的使用:
可以调用当前类的属性、方法。
方法中不能定义方法。
方法的重载
1.理解方法的重载:
(overload)方法的重载:在同一个类中,允许存在方法同名,但是他们的形参要不一样
√ 返回值不同不算重载
public void getSum(int i ,int j){}
public void getSum(int i,char j){}
public void getSum(char i,int j){}
//无法定义同名返回值不同的方法
// public int getSum(int i,char j){ return 0;}
方法的重写
方法的重写(override/overwrite):子类中的叫重写的方法,父类中的叫被重写的方法
1.子类重写的方法名和形参列表与父类被重写的方法的形参列表相同。
2.权限修饰符 : 子类重写的方法的权限修饰符 >= 父类中的权限修饰符
>特殊情况:子类不能重写父类中权限为private的方法
3、返回值类型:
> 父类被重写的方法的返回值类型是基本数据类型 ,则子类重写的方法的返回值只能是基本数据类型
> 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值只能是A或A类的子类
4.子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型
** 子类和父类中的同名同参数的方法,要么都声明为非static(考虑重写),要么都声明为static(不是重写)
面试题:区别方法的重载与重写
重载是,有着不同形参的不同方法,是在同一个类中的
重写,是在子类中继承父类的方法后,进行的覆盖
可变个数的形参
可变个数的形参:
JDK5.0之前:使用数组表示可变个数。
JDK5.0之后:使用String...strs表示可变个数
public void show(String[] strs);
与
public void show(String ... strs);
在系统眼中是一样的方法
可变参数必须写在其他参数的后面
public void show(int i,String ...j);
可变参数在一个方法中只能使用一次
public void show(int ... i,String ... j);
值传递问题swap(n,m)
方法参数的值传递机制
System.out.println("基本数据类型:");
int m = 10;
int n = m;
System.out.println("m = " + m + ", n = " + n);
n = 20;//不会改变m的值
System.out.println("m = " + m + ", n = " + n);
System.out.println("应用数据类型");
Person p1 = new Person();
p1.age = 20;
Person p2 = new Person();
p2 = p1;
System.out.println("p1.age = " + p1.age + " p2.age = " + p2.age);
p2.age = 30;
System.out.println("p1.age = " + p1.age + " p2.age = " + p2.age);
结果如下:
基本数据类型:
m = 10, n = 10
m = 10, n = 20
应用数据类型
p1.age = 20 p2.age = 20
p1.age = 30 p2.age = 30
形参的值传递
形参的值传递 :
基本数据类型:在方法中swap只是在方法体内的改变 , 实际上不改变。
because: 因为传递到方法中的m和n是在栈中新建的一个m和n,所以main中的m和n不会改变。
引用数据类型:在方法中swap改变实际的m和n
because: 因为传递到方法中的m和n是在栈中建立一个指向对象的指针,而修改是在该地址上修改,所以m和n会改变。
构造器
class Person{
String name;
int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
代码块
1.代码块的作用:用来初始化类、对象
2.代码块如果由修饰的化,只能使用static
3.静态代码块 vs 非静态代码块
静态代码块:
1.随着类的加载而执行,而且只执行一次
非静态代码块
1.随着对象的创建而执行,每创建一次就执行一次
2.作用:可以在创建对象时,对对象的属性进行初始化。
public class test {
public static void main(String[] args) {
myclass myclass = new myclass();
//static 代码块
//代码块
myclass myclass1 = new myclass();
//代码块
}
}
class myclass{
static {
System.out.println("static 代码块");
}
{
System.out.println("代码块");
}
}
内部类
内部类:当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么这个内部的完整结构最好是使用内部类。
/*
内部类:当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构
又只为外部事物提供服务,那么这个内部的完整结构最好使用内部类。
*/
public class day15_24 {
public static void main(String[] args) {
// 1.如何实例化成员内部类的对象
Class.InnerClass1 in1 = new Class1.InnerClass1();
in1.show();
Class in2 = new Class1();
Class.InnerClass2 in2in2 = in2.new InnerClass2();
in2in2.show();
}
}
class Class1{
/* 1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类 */
/* 2.内部类的分类:成员内部类 vs 局部内部类 */
/* 成员内部类:
一方面,作为外部类的成员
> 调用外部类的结构
> 可以被static修饰
> 可以被4种不同的权限修饰
另一方面,作为一个类:
> 类内可以定义属性,方法,构造器
> 可以被final修饰,表示此类不能被继承,
> 可以被abstract修饰,表示不能是实例化
*/
/*
三个问题
1.如何实例化成员内部类的对象
2.如何在成员内部类中区分调用外部类的结构
3.开发中局部内部类的使用
*/
//静态成员内部类
static class InnerClass1{
String name;
public InnerClass1(){
}
public void show(){
System.out.println("this is innerclass111");
}
}
//成员内部类
class InnerClass2{
String name;
public InnerClass2(){
}
public void show(){
System.out.println("this is innerclass222");
}
}
}
局部内部类的方法 (比如 :show) 如果调用局部内部类所声明的方法(比如:method )中的局部变量(比如num)要求此局部变量声明为final
public class day16_05 {
public void method(){
int num = 10;
class AA{
public void show(){
// num = 22;
System.out.println(num);
}
}
}
}
封装性
封装与隐藏:
程序设计追求:高内聚,低耦合
高聚合:类的内部数据操作细节自己完成,不允许外部干涉
低耦合:仅对外暴露少量的方法用于使用
封装性的设计思想:把该隐藏的隐藏起来,把该暴露的暴露出来。
封装性的体现:
① 我们将类的属性私有化,同时提供共有的get、set方法来使用属性
② 不对外暴露的私有的方法
③ 单例模式
封装性的体现,需要权限修饰符来配合
1.Java规定的四种权限:private、缺省(default)、protected、public
private(类内部)
缺省(同一个包内)
protected(不同包的子类)
public(同一个工程)
2.权限修饰符可以用来修饰类及类的内部结构:属性、方法、构造器、内部类。
修饰类:public、缺省
3.总结:Java提供了4种权限修饰符来修饰类及类的内部结构,体现类及类的内部结构在调用时的可见性大小。
public class Encapsulation{
public static void main(String[] args) {
ClassA demo = new ClassA();
//封装性:将一些不能暴露在外面的属性或方法私有化
demo.age = 1;/*不能直接使用 */
//必须通过set\get方法调用
demo.setage(1);
int age = demo.getage();
}
}
class ClassA{
private int age;
public void setage(int age){
this.age = age;
}
public int getage(){
return this.age;
}
}
继承性
继承性:inherence
1.继承性的好处
① 减少了代码的冗余,提高了代码的复用性。
② 便于功能的拓展
③ 为之后多态性的使用,提供了前提
2.继承性的格式:class A extends B{}
A:子类、派生类(subclass)
B:父类、超类、基类(superclass)
体现:一旦子类A继承父类B以后,子类A种就获取了父类B种声明的结构、属性、方法
Java中关于继承性的规定:
1.一个父类可以有多个子类
2.一个类只能有一个父类
3.子父类是相对的概念
4.子类直接继承的父类,称为:直接父类。间接继承的父类称为:间接父类
5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法
四、
1.如果我们没有显式的声明一个类的父类的话,则此类继承于Object类
public class day11_20to23 {
public static void main(String[] args) {
Student s = new Student("tom",22,"Computer Science");
s.eat();
//如果Person类中的属性私有化
//Student对象仍然能够操作Person类中的属性
s.setAge(10);
System.out.println(s.getAge());
Person p = new Person();
}
}
class Person {
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
class Student extends Person{
// String name;
// int age;
String major;
public Student(){
}
public Student(String name, int age, String major) {
super(name,age);
this.major = major;
}
public void study(){
System.out.println("students studying");
}
@Override
public void eat() {
System.out.println("students eat");
}
@Override
public void sleep() {
System.out.println("students sleep");
}
}
继承性练习:
为什么要提供空参public的构造器?
因为在数据库创造对象时,最简单需要创建一个空的对象。
多态性
多态性 Man m = new Person2();
1.可以调用man中重写的方法
2.无法调用man中的属性
3.无法调用man中特有的方法
为什么要使用多态性?
public class day12_18 {
public static void main(String[] args) {
day12_18 d = new day12_18();
d.func(new Dog());
d.func(new Cat());
如果没有多态性:我们在func方法内只能new Person()
如果要使用func(new Cat())那就需要重载一个func方法
}
public void func(Animal animal){
animal.eat();
animal.shout();
}
}
class Animal{
public void eat(){System.out.println("eat");}
public void shout(){System.out.println("shout");}
}
class Dog extends Animal{
@Override
public void eat() {System.out.println("dag eat");}
@Override
public void shout() {System.out.println("dog shout");}
}
class Cat extends Animal{
@Override
public void eat() {System.out.println("cat eat");}
@Override
public void shout() {System.out.println("cat shout");}
}
多态性不适用于属性
public class day12_19 {
public static void main(String[] args) {
p1 x1 = new p1();
System.out.println(x1.id);
p2 x2 = new p1();
System.out.println(x2.id);//如果有多态性则应该是 1;
}
}
class p1 extends p2{
int id = 1;
}
class p2{
int id =2 ;
}
虚拟方法调用:我们将父类中被重写的方法称为虚拟方法
多态是编译时行为还是运行时行为?
运行时行为。
向下转型
/* 向下转型的使用 */
Person p1 = new Man();
/* 不能使用Man中的特有的方法 */
// p1.earnMoney();
// p1.isSmoking = true;
/* 内存中是否有 earnMoney() 和 isSmoking属性呢 :
有 , 只是由于我们声明为父类类型,我们调不了。*/
/* 如何才能调用子类特有的属性和方法 ?*/
Man m1 = (Man)p1;
m1.earnMoney();
m1.eat();
m1.setSmoking(true);
System.out.println(m1.isSmoking());
instanceof关键字
/* instanceof :为了避免classCastException的异常 */
/*
a instanceof A :判断对象a是否是类A的实例
如果是,返回true
如果不是,返回false
*/
Person p1 = new Man();
if(p1 instanceof Woman){
Woman p2 = (Woman)p1;
p2.goShopping();
}
else{
Man p3 = (Man)p1;
p3.earnMoney();
}
if(p1 instanceof Person){
System.out.println("person");
}
if(p1 instanceof Object){
System.out.println("object");
}
模板设计模式
public class day15_11 {
/*
多态的应用:模板方法设计模式
1.当功能内部一部分实现是确定的,一部分是不确定的,这是可以把不确定部分暴露出来,让子类去实现
2.换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些
部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板。
Template
*/
public static void main(String[] args) {
SubTemplate subTemplate = new SubTemplate();
subTemplate.spendTime();
}
}
abstract class Template{
public void spendTime(){
long start = System.currentTimeMillis();
code();
long end = System.currentTimeMillis();
System.out.println("花费时间为 " + (end - start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i = 2;i <= 1000;i++){
boolean isFlag = true;
for(int j = 2;j<= Math.sqrt(i);j++){
if(i % j == 0){
isFlag = false;
break;
}
}
if(isFlag){
System.out.println(i);
}
}
}
}
JDK7.0以前的接口
解决了类,单继承性的缺点
实现了相同接口的不同类,但是各个类之间没有直接的关系
实现接口后,类也具有了接口中的功能。
接口 Interface
java中,接口和类是并列的结构
如何定义接口:
定义接口中的成员
1.JDK7及以前:
只能定义全局常量和抽象方法
全局常量:public static final的
抽象方法:public abstract的
2.JDK8:还可以定义静态方法、默认方法
3.接口中不能定义构造器,意味着接口不能实例化。
4.Java开发中,都是让类来实现接口来使用接口。
如果实现类覆盖了接口的所有抽象方法,才可以实例化
否则他还是一个抽象类
6.Java类可以实现多个接口
7.接口和接口之间可以继承,而且可以多继承
8.接口的具体使用,体现了多态性
9.接口,实际上可以看作是一种规范
public class day15_14to17 {
/*
接口 Interface
java中,接口和类是并列的结构
如何定义接口:
定义接口中的成员
1.JDK7及以前:
只能定义全局常量和抽象方法
全局常量:public static final的
抽象方法:public abstract的
2.JDK8:还可以定义静态方法、默认方法
× 接口中不能定义构造器,意味着接口不能实例化。
Java开发中,都是让类来实现接口来使用接口。
如果实现类覆盖了接口的所有抽象方法,才可以实例化
否则他还是一个抽象类
6.Java类可以实现多个接口
7.接口和接口之间可以继承,而且可以多继承
*/
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferData(flash);
//2. 创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3. 创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
com.transferData(phone);
//4. 创建了接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
/* 多态性的体现 */
public void transferData(USB usb){
usb.start();
System.out.println("具体细节");
usb.stop();
}
}
interface USB{
//常量:定义了长宽高最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("flash start");
}
@Override
public void stop() {
System.out.println("flash stop");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("printer start");
}
@Override
public void stop() {
System.out.println("priter stop");
}
}
JDK8.0之后的接口
interface CompareA{
//全局常量
public static final int I = 1;
int J = 2;
//抽象方法
public abstract void method11();
void method12();
//静态方法
public static void method(){
System.out.println("CompareA:北京");
}
//默认方法
public default void method2(){
System.out.println("CompareA:上海");
}
//public 可以省略
default void method3(){
System.out.println("CompareA:上海");
}
}
代理模式
public class day15_18 {
/*
接口应用:代理模式
*/
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
Object类
Object是所有Java类的根部类
如果一个类,没有显示的继承一个类,则它的父类为Object
finalize()方法:永远不要主动调用fianalize()
equals()方法:
只适用于引用数据类型
自定义类调用的是Object中的equals()方法,比较地址
String调用的是String中的重写的equals()方法,比较的是字符串是否相同
包装类
基本数据类型 --> 包装类
byte ---------> Byte
short---------> Short
[ int --------> Integer]
long ---------> Long
float --------> Float
double -------> Double
boolean ------> Boolean
[char --------> Character]
为什么要定义包装类呢:
因为基本数据类型跟object没有关系,定义包装类之后,才将基本数据类型与Object联系在一起
自动装箱和自动拆箱
//自动装箱
Integer num1 = num;
//自动拆箱
int num2 = num1;
基本数据类型与String的相互转换
/* 基本 ---> String */
int num1 = 10;
//方式一:连接运算
String str1 = num1 + "";
System.out.println(str1);
//方式2:valueof()
String s = String.valueOf(456);
System.out.println(String.valueOf('a'));
System.out.println(s);
/* String ---> 基本*/
String str = "123";
//调用包装类中的方法
int i = Integer.parseInt(str);
System.out.println(i);
String str2 = "true";
boolean b = Boolean.parseBoolean(str2);
System.out.println(b);
String str3 = "123.2";
float v = Float.parseFloat(str3);
System.out.println(v);
基本数据类型 ---> 包装类,调用包装类的构造器
int num1 = 10;
Integer int1 = new Integer(num1);
System.out.println(int1.toString());//10
Integer int2 = new Integer("213");
System.out.println(int2);//213
Float f1 = new Float(12.3f);
Float f2 = new Float("12.3");
System.out.println(f1);
System.out.println(f2);
Boolean b1 = new Boolean(true);
Boolean b2 = new Boolean("true");
Boolean b3 = new Boolean("true123");
System.out.println(b1 + " " + b2 + " " + b3);//true true false;
包装类转换为基本数据类型:
因为包装类无法进行加减乘除运算
只有转换为基本数据类型才能进行运算
int j = in1.intValue();
System.out.println(j + 1);
Float f1 = new Float("123.2");
float f2 = f1.floatValue();
其他
JavaBean
JavaBean是一种Java语言写成的可重用组件
所谓JavaBean,是指符合如下标准的Java类
1.类是公共的
2.有一个无参的公共的构造器
3.有属性,且有对应的get、set方法
package关键字
package关键字的使用
1.为了更好的实现项目中的管理,提供了包的概念。
2.使用package声明类或接口所属的包,写在文件的首行。
3.包,属于标识符,遵循标识符的命名规则、规范(),见名知意
4.每"."一次,就代表一层文件目录
MVC设计模式
MVC设计模式:
MVC是常用的设计模式之一,将整个程序设计分为三个层次:
视图模型层,控制器层,数据模型层
这种将程序输入输出、数据处理,以及数据的展示分离开来的设计模式,使程序结构变的灵活而且清晰,同时也描述了程序各个对象间的通信方式,降低了程序的耦合性。
模型层:model主要处理数据
数据对象封装:model.bean/domain
数据库操作类:model.dao
数据库:medel.db
控制层:controller 处理业务逻辑
应用界面相关 controller.activity
存放fragment controller.fragment
显示列表的适配器 controller.adapter
服务相关的 controller.service
抽取的基类 controller.base
视图层 view显示数据
相关工具类 view.utils
自定义view view.ui
import关键字
import关键字的使用
1.在源文件中显式的使用import结构导入指定包下的类、接口
2.声明在包的声明和类的声明之间
3.如果需要导入多个,并列
4.util.* 表示导入util类的所有结构
5.核心包java.lang,则省略。
6.同一个包内定义的类,则可以省略。
7.如果在源文件中,使用了不同包下的类,则需要用全类名
8.如果使用“xxx.*"方式可以调用xxx包下的所有结构,但是如果使用xxx子包下的类,仍然需要导入。
9.import static:导入指定包或类中的static结构
super关键字
super关键字的使用:
1.super理解为:父类的
2.super可以用来调用:属性、方法、构造器
3.super的使用:
调用属性:同名属性 this表示此类中,super表示父类中
调用方法:重写的方法 this表示此类中,super表示父类中。
调用构造器:1.我们可以使用super(形参列表)的方式调用父类构造器,或 this(形参列表)调用自己的构造器
2.super this 必须在首行
3.this和super只能使用一个
4.默认调用父类中的空参构造器
5.在类的多个构造器中,至少有一个类的构造器使用super,没有就是隐藏了
static关键字
static的引入
我们希望某些特定的数据在内存空间里只有一份
static可以用来修饰:属性、方法、代码块、内部类
static修饰属性
1.静态变量随着类的加载而加载
2.实例变量随着对象的加载而加载
由于类只加载一次,则静态变量也只存在一份;存在方法区的静态域中。
static修饰方法
静态的方法中,只能调用静态的方法 或 属性
在静态的结构中,不能使用this 、 super关键字
main方法
main方法的使用说明
1.main()方法作为程序的入口
2.mina()方法也是一个普通的静态方法
3.mian()方法的形参可以作为我们与控制台交互的方式
final关键字
public class day14_24 {
final可以用来修饰:类、方法、变量
1.final 修饰一个类:
final类不能被继承:比如:String类、System类、StringBuffer类
2.final 用来修饰方法:
final方法不能被重写:比如:Object.getclass()、
3.final修饰变量
final变量就是一个常量
final修饰属性时:可以初始化时候赋值、构造器中初始化、代码块中
final修饰局部变量:
static final:只能用来修饰属性:全局常量
方法:
单例设计模式
就是采取一定的方法保证在整个软件系统中,对某个类之恶能存在一个对象实例,
并且该类只提供一个取得其对象实例的方法。
如果我们要让类在一个虚拟机中之只能产生一个对象,我们首先必须将
1.类的构造器的访问权限设置为private,这样,就不能用new操作符在类的外部产生类的对象了,
但是在类的内部仍可以使用该类的对象。因此,在类的外部开始还无法得到类的对象。
2.只能通过该类的某个静态方法,以返回类内部创建的该类的对象,静态方法只能访问类中的静态成员变量,
所以,指向类内部产生的该类对象的变量也必须定义成静态的。
public class day14_15 {
public static void main(String[] args) {
/* Singleton 饿汉式 */
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);//true
}
}
class Bank{
//1.私有化类的构造器
private Bank(){
//为了避免在类外部创建多个对象
}
//2.内部创建类的对象
private static Bank instance = new Bank();
//3.提供公共的方法,返回类的对象
public static Bank getInstance(){
return instance;
}
}
public class day14_16 {
public static void main(String[] args) {
/* singleton 懒汉式 */
Order o1 = Order.getInstance();
Order o2 = Order.getInstance();
System.out.println(o1 == o2);
}
}
class Order{
private Order(){
}
private static Order instance = null;
public static Order getInstance(){
if(instance == null) instance = new Order();
return instance;
}
}
区分饿汉式 和 懒汉式
饿汉式:
坏处:对象加载时间过长
好处:饿汉式式线程安全的
懒汉式:
好处:延迟对象的创建
坏处:线程不安全 --> 多线程中可以修改为线程安全的
abstract关键字
抽象类:由于子类越来越多,父类不在会使用,则将父类定义为抽象类
√ 抽象类不能实例化,那么构造器有什么用呢:供子类对象实例化来使用
/* abstract 的一些细节 */
1.abstract不能用来修饰:属性、构造器等结构
2.abstract不能用来修饰私有方法、静态方法、final的方法。
abstract的使用
public class day15_06 {
public static void main(String[] args) {
}
}
abstract class Creature{
public abstract void breath();
}
abstract class Perosn extends Creature{
String name;
int age;
public Perosn(String name, int age) {
this.name = name;
this.age = age;
}
public Perosn() {
}
/* 抽象方法只有声明,没有方法体:仅供子类重写 */
//Abstract methods cannot have a body
// public abstract void eat(){
// System.out.println(" Person eat");
// }
/* 包含抽象方法的类,一定是抽象类 */
public abstract void eat();
}
class Student extends Perosn{
/* 抽象的方法在子类中必须重写 */
/* 如果子类不重写抽象方法,则子类必须声明为abstract */
@Override
public void eat() {
System.out.println("student eat");
}
/* 父类继承的抽象方法也要重写 */
@Override
public void breath() {
System.out.println("student breath");
}
}
1.为什么抽象类不可以用final去修饰
因为final表示不能继承,abstract就是要去被继承
2.一个抽象类类种可以定义构造器吗
可以
3.是否可以这样理解:抽象类就是比普通类多定义了抽象方法,除了不能进行类的实例化之外没有什么不同
** 抽象类的匿名子类**
public class day15_10 {
public static void main(String[] args) {
// 匿名对象
method(new Student());
/* 匿名类 */
Perosn p = new Perosn() {
@Override
public void eat() {
System.out.println("翅鸫i下");
}
@Override
public void breath() {
System.out.println("呼吸");
}
};
method(p);
}
public static void method(Perosn s){
s.eat();
s.breath();
}
}
异常处理
Java语言中,将程序执行中发生的不正常情况称为“异常”(开发过程中的语法错误和逻辑错误不是异常)
Error:
Java虚拟机无法解决的严重问题。如:JVM系统内部错误,资源耗尽等严重情况
Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性
的代码进行处理。例如:
1.空指针访问
2.试图读取不存在的文件
3.网络连接中断
4.数组角标越界
/* error */
java.lang.StackOverflowError
java.lang.Stack
异常体系结构
java.lang.Throwable
1.java.lang.Error:一般不编写针对性代码进行处理
2.java.lang.Exception:可以进行异常的处理
编译时异常(checked)
①IOException
FileNotFoundException
② ClassNotFoundException
运行时异常(unchecked)
NullPointerException
ArrayIndexOutOfBoundsException
ClassCastException
InputMisMatchException
public class day16_07 {
@Test
public void test1(){
//NullPointerException
int[] arr = null;
System.out.println(arr);
}
@Test
public void test2(){
//ArrayIndexOutOfBoundException
String str = "abc";
System.out.println(str.charAt(3));
}
@Test
public void test3(){
//ClassCastException
Object obj = new Date();
String str = (String)obj;
}
@Test
public void test4(){
//NumberFormatException
String str = "123";
int num = Integer.parseInt(str);
String str1 = "afa";
int num1 = Integer.parseInt(str1);
}
@Test
public void test5(){
//InputMismatchException
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();//当你输入错误时
System.out.println(score);
}
@Test
public void test6(){
//ArithmeticException
int a = 10;
int b = 0;
System.out.println(a/b);
}
@Test
public void test7() throws IOException {
//编译时异常
File file = new File("hello.txt");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data != -1){
System.out.println((char)data);
data = fis.read();
}
fis.close();
}
}
try-catch-finally
异常的处理:抓抛模型
过程一:“抛”,程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。
将此对象抛出,一旦抛出对象后,其后的代码不在执行
过程二:“抓”,可以理解为异常的处理方式:① try-catch-finally ② throws
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式
}catch(异常类型2 变量名2){
}
....catch(){
}finally{
//将一定会执行的代码
}
说明:
- finally是可选的。
- 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象
的类型,去catch中进行匹配 - 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
try-catch结构(在没有写finally的情况)。继续执行其后的代码 - catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错 - 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
- 在try结构中声明的变量,再出了try结构以后,就不能再被调用
- try-catch-finally结构可以嵌套
体会:
-
使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
-
开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。针对于编译时异常,我们说一定要考虑异常的处理。
throws + 异常处理
-
"throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常
类型时,就会被抛出。异常代码后续的代码,就不再执行! -
体会:try-catch-finally:真正的将异常给处理掉了。
throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉。 -
开发中如何选择使用try-catch-finally 还是使用throws?
- 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式处理。
- 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws 的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
手动抛出异常:throw
public class day16_16 {
public static void main(String[] args) {
Student s = new Student();
try {
s.regist(-1001);
} catch (Exception e) {
System.out.println(e.getMessage());
}
System.out.println(s);;
}
}
class Student{
private int id;
public void regist(int id) throws Exception{
if(id > 0){
this.id = id;
}
else{
// throw new RuntimeException("您输入的数据非法!");
throw new Exception("您输入的数据非法");
}
}
}
用户自定义异常
//1.继承于现有的异常结构:RuntimeException 、Exception
public class day16_17 extends RuntimeException{
static final long serialVersionUID = -7034897190745766939L;
public day16_17(){
}
public day16_17(String msg){
super(msg);
}
}
本文介绍了面向对象编程的基本概念,包括类和对象、属性与方法、构造器与代码块等内容,并详细解释了面向对象的三大特性:封装性、继承性和多态性。
8万+





