/* 1. 面向对象概念(Java中一切皆对象) 1.1. 面向对象是相对面向过程而言的 1.2. 面向对象和面向过程都是一种思想 1.3. 面向过程 a. 强调的是功能行为,面向过程是一种思想 1.4. 面向对象 a. 将功能封装进对象,强调具备了功能的对象, 找到功能对应的事物,将功能封装进事物,以后 就操作这个事物就可以了,将复杂的问题简单化 将我们的角色由执行者转变为指挥者 1.5. 面向对象是基于面向过程的 1.6. example */ class NewDemo1 { public static void main(String[] args) { System.out.println("Hello World!"); } /* 定义对象的方法1: 名词提炼法。 例: 人开门 人 { 开门(门) { 门.开(); } } 门 { 开(){操作门轴...}; } */ } /* 2. 面向对象的三大特性: 封装, 继承, 多态. 2.2. 类与对象的关系 2.2.1. 类就是对现实生活中事物的描述,对象就是这类事物,实实在在存在的个体 2.3. example 需求:描述汽车(颜色,轮胎数),描述事物其实就是在描述事物的属性和行为 属性对应类中的变量,行为对应类中的函数(方法) 其实定义类就是在描述事物,就是在定义属性和行为,属性和行为共同称为 类中的成员(成员变量和成员方法) */ class Car { //描述颜色 String color = "red"; //描述轮胎数 int num = 4; //运行行为.行为对应方法 void run() { System.out.println(color + ".." + num); } //这里发现一个问题,我们的类没有主函数。 //答:主函数的作用在于让一个类独立运行,当我们的类只为了描述事物的时候就不需要主函数 // 只要建立这个类的对象,随时都可以使用此类中的东西,这就是面向对象的特点 } class CarDemo1 { public static void main(String[] args) //主函数就是一个入口,用于调用其他事物 { //生产汽车,在Java中通过new操作符来完成的 Car c = new Car(); //c就是一个类类型变量,记住:类类型变量指向对象 //需求:将已有车的颜色改成蓝色,指挥该对象做事情,在Java中指挥方式是:对象.对象成员 c.color = "blue"; //让车运行起来 c.run(); } } /* 2.4. 成员变量和局部变量 2.4.1. 作用范围 a)成员变量作用于整个类中 b)局部变量作用于函数中,或者语句中 2.4.2. 在内存中的位置 a)成员变量:在堆内存中,因为对象的存在,才在内存中存在. b)局部变量:存在于栈内存中 2.5. 匿名对象 2.5.1. 匿名对象是对象的简化形式 2.5.2. 匿名对象两种使用情况: a)当对对象方法仅进行一次调用时 b)匿名对象可以作为实际参数进行传递 2.5.3. example */ class Car { String color = "red"; int num = 4; void run() { System.out.println(color + ".." + num); } } class CarDemo2 { public static void main(String[] args) { //Car c = new Car(); //c.num = 5; 这两句话可以简写成一句话 new Car().num = 5; new Car().color = "blue"; //匿名对象调用属性没有意义,因为执行完毕之后,在堆内存中就称为垃圾了 new Car().run(); //调用方法有意义,因为方法中可以有内容 /*总结:匿名对象 a)使用方法1:当对对象的方法仅进行一次调用时使用,这样写比较简化,可是如果对一个对象进行多个成 调用,必须给这个对象起个名字 b)可以将匿名对象作为实际参数传递 example 需求:汽车修配厂,对汽车进行改装,将来的车改成黑车,三个轮胎 */ Car q = new Car(); show(q); //show(new Car()); //这就叫匿名对象可以作为实际参数传递,此种做法会在堆能村中产生垃圾 } public static void show(Car c) //汽车修配厂功能 { c.num = 3; c.color = "black"; c.run(); } } /* 2.5. 面向对象的第一大特性:封装 2.5.1. 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式 2.5.2. 好处: a)将变化隔离:所有更改对于调用者来说是透明的 b)便于使用 :不用了解封装内部的构造 c)提高重用性:便于代码的复用性 d)提高安全性:不必要了解细节,提高安全性 2.5.3. 封装原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共方法对其访问 2.5.4. example */ class { public static void toBin() { trans(); } public static void toHex() { trans(); } private static void trans() //这里把次函数进行封装 { System.out.println("Hello World!"); } } //2.5.5. private修饰符(私有) class Person { int age; void speak(); { System.out.println("age= " + age); } } class PersonDemo1 { public static void main(String[] args) { Person p = new Person(); p.age = -20; //这里能修改成-20,与现实生活中不符合,造成这种原因是age属性能直接访问 p.speak(); } } //所以我们用private修饰符来修饰其属性,私有仅仅是封装的一种表现形式 class Person { private int age; //私有属性只在本类中有效,类以外即使建立了对象也不能直接访问。 //但是人应该有年龄,就需要在Person类中提供对应的访问age的方式 public void setAge(int a) //对外提供的方法通常是set,返回通常是void { if(age>0 && <130) age = a; speak(); else System.out.println("年龄非法"); } public int getAge() //get表示获取,返回类型一般和变量类型一样 { return age; } void speak(); { System.out.println("age= " + age); } } class PersonDemo2 { public static void main(String[] args) { Person p = new Person(); //p.age = -20; //这里不能在访问了,会报错 p.setAge(20); //这里调用公共访问插口 p.speak(); } } /* 构造函数 特点: 1.函数名与类名相同 2.不用定义返回值类型 3.不可以写return语句 作用:给对象进行初始化 注意: 1.默认构造函数的特点 2.多个构造函数是以重载的形式存在的 example: */ class Person { private String name; private int age; Person() //构造函数对象已建立就会调用与之对应的构造函数 { System.out.println("A: Name=" + name + ",age=" + age); } Person(String name) { name = n; System.out.println("B: name=" + name + ",age" + age); } Person(String n,int a) { name = n; age = a; System.out.println("C: name=" + name + ",age" + age); } } class PersonDemo3 { public static void main(String[] args) { Person p = new Person(); Person p1 = new Person("lisi"); Person p2 = new Person("lisi",10); } } /* 构造代码块 作用:给对象进行初始化 对象一建立就运行,而且优先于构造函数执行 和构造函数的区别: 1.构造代码块是给所有对象进行统一初始化而构造函数是给对应的对象初始化 */ class Person { { System.out.println("Hello world!"); //把所有对象共性的内容放到构造代码块中就可以了 } } class PersonDemo4 { public static void main(String[] args) { Person p = new Person(); } } /* this关键字:用于区分局部变量和成员变量同名的情况 this代表它所在函数,所属对象的引用,简单说,哪个 对象在调用this所在的函数,this就代表那个对象 */ class Person { private String name; //this.name 表示局部变量 private int age; Person() { System.out.println("A: Name=" + this.name + ",age=" + this.age); } Person(String name) { this.name = name; System.out.println("A: Name=" + this.name + ",age=" + this.age); } Person(String name,int age) { this.name = name; this.age = age; System.out.println("A: Name=" + this.name + ",age=" + this.age); } } class PersonDemo5 { public static void main(String[] args) { Person p = new Person(); } } //this关键字的应用 class Person { private String name; private int age; Person() { this.age = 18; } Person(int age) { this.age = age; } //需求:给人一个用于比较年龄是否相同的功能 public void compare(int age) { if(this.age == age) System.out.println("同龄人"); else System.out.println("不是同龄人"); } } class PersonDemo6 { public static void main(String[] args) { Person p = new Person(20); p.compare(20); } } //this关键字在构造函数间调用 //this语句只能定义在构造函数的第一个语句,因为初始化动作要先执行 class Person { private String name; private int age; Person(String name) { this.name = name; } Person(String name,int age) { //this.name = name; //这里其实多余了,因为上面的函数封装过this.name功能了 this(name); //利用this关键字来调用本类中的Person对象 this.age = age; } } class StaticDemo1 { public static void main(String[] args) { Person p = new Person("lisi",30); } } /* static(静态)关键字 static是一个修饰符,用于修饰成员(成员变量,成员函数) 当成员被静态修饰后,就多了一个调用方式,除了可以被 对象调用外,还可以直接被类名调用。类名.静态成员 static特点: 1.随着类的加载而加载,随着类的消失而消失 2.优先与对象存在 3.被所有对象所共享 4.可以直接被类名所调用 静态使用注意事项: 1.静态方法只能访问静态成员 非静态方法既可以访问静态也可以访问非静态 2.静态方法中不可以定义this,super关键字 因为静态优先于对象存在,所以静态方法中不可以出现this 静态有利有弊 利:对对象的共享数据进行单独空间存储,节省空间,没有必要每一个对象中都存储一份,可以直接被类调用 弊:生命周期过长,访问出现局限性(静态虽好,只能访问静态) 主函数是静态的 */ class Person { String name; //成员变量,实力变量 static String country = "CN"; //static修饰符表示在内存中只存在一份,存放在内存中的方法区中 public void show() { System.out.println(name + "::" + country); } } class StaticDemo2 { public static void main(String[] args) { Person p = new Person(); p.name = "zhangsan"; p.show(); System.out.println(Person.country); //利用类名调用,因为static存在与内存中 } } /* 主函数:是一个特殊的函数,程序的入口,可以被Jvm调用 主函数的定义: public //代表该函数的访问权限是最大的 static //代表该函数随着类的加载就已经存在了 void //主函数没有具体的返回值 main //不是关键字,但是是一个特殊的单词,可以被Jvm识别 (String[] arr) //函数的参数,存储字符串类型的元素的数组 Jvm在调用主函数时,传入的是new String[0]; */ class MainDemo { public static void main(String[] args) { System.out.println(args[0]); } //public static void main(int x) //这里不会报错,会重载 //{ //} } /* 什么时候使用静态? 1.什么时候定义静态的变量(类变量)呢? 答:当对象中出现共享数据时(值) 2.对象中的特有数据要定义成非静态存在于堆内存中 什么时候定义静态函数呢? 1.当功能内部没有访问到非静态数据(对象的特有数据)那么该功能可以定义成静态的 */ class Person { String name; public static void show() //当功能内部没有访问到非静态数据(对象的特有数据)那么该功能可以定义成静态的 { System.out.println("haha"); } } class PersonDemo7 { public static void main(String[] args) { //Person p = new Person(); //这里就不必要这么写 //p.show(); Person.show(); } } /* 静态的应用 1.把所有需要经常使用功能重复的功能定义在一个类里面 2.没有操作任何数据的方法都定义成静态方法 */ class ArrayTool { /* 将方法都静态后,可以方便于使用,但是该类还是可以被其他程序建立对象 为了更加严谨,强制让该类不能建立对象,可以通过将构造函数私有化完成 */ private ArrayTool(){} public static int getMax(int[] arr) { int max = 0; for(int x=1; x<arr.length; x++) { if(arr[x]>arr[max]) max = x; } return arr[max]; } public static int getMin(int[] arr) { int min = 0; for(int x=1; x<arr.length; x++) { if(arr[x]<arr[min]) min = x; } return arr[min]; } public static void selectSort(int[] arr) { for(int x=0; x<arr.length-1; x++) { for(int y=x+1; y<arr.length; y++) { if(arr[x]>arr[y]) { swap(arr,y,y+1); } } } } public static void bubbleSort(int[] arr) { for(int x=0; x<arr.length-1; x++) { for(int y=0; y<arr.length-x-1; y++) { if(arr[y]>arr[y+1]) { swap(arr,y,y+1); } } } } private static void swap(int[] arr,int a,int b) { int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } } class ArrayToolDemo { public static void main(String[] args) { int[] arr = {3,5,2,6,98,1}; int max = ArrayTool.getMax(arr); //使用我们定义的工具类 System.out.println("Max=" + max); } } /* 帮助文档的制作 Java的说明书通过文档的注释来完成 Javadoc来生成说明书 */ /** 这是一个可以对数组进行操作的工具类,该类提供了,获取最值,排序等功能。 @author 张三 @version v1.0 */ public class ArrayTool //这里必须用public来修饰 { /** 空参数构造函数 */ private ArrayTool(){} /** 获取一个整形数组中的最大值。 @param arr 接受一个int类型的数组。 @return 会返回一个该数组中的最大值。 */ public static int getMax(int[] arr) { int max = 0; for(int x=1; x<arr.length; x++) { if(arr[x]>arr[max]) max = x; } return arr[max]; } /** 获取一个整形数组中的最小值。 @param arr 接受一个int类型的数组。 @return 会返回一个该数组中的最小值。 */ public static int getMin(int[] arr) { int min = 0; for(int x=1; x<arr.length; x++) { if(arr[x]<arr[min]) min = x; } return arr[min]; } /** 给int数组进行选择排序。 @param arr 接收一个int类型的数组。 */ public static void selectSort(int[] arr) { for(int x=0; x<arr.length-1; x++) { for(int y=x+1; y<arr.length; y++) { if(arr[x]>arr[y]) { swap(arr,y,y+1); } } } } /** 给int数组进行冒泡排序。 @param arr 接收一个int类型的数组。 */ public static void bubbleSort(int[] arr) { for(int x=0; x<arr.length-1; x++) { for(int y=0; y<arr.length-x-1; y++) { if(arr[y]>arr[y+1]) { swap(arr,y,y+1); } } } } /** 给数组中的元素进行位置的置换 @param arr 接收一个int类型的数组。 @param a 要置换的位置 @param b 要置换的位置 */ private static void swap(int[] arr,int a,int b) { int temp = arr[a]; arr[a] = arr[b]; arr[b] = temp; } } class ArrayToolDemo { public static void main(String[] args) { int[] arr = {3,5,2,6,98,1}; int max = ArrayTool.getMax(arr); //使用我们定义的工具类 System.out.println("Max=" + max); } } /* 静态代码块 格式: static { 执行语句; } 特点:随着类的加载而执行,只执行一次,用于给类进行初始化的 */ class StaticCode { static //静态优先于主函数执行 { System.out.println("a"); } } class StaticCodeDemo { static //静态优先于主函数执行 { System.out.println("b"); } public static void main(String[] args) { new StaticCode(); new StaticCode(); System.out.println("over"); } static //静态优先于主函数执行 { System.out.println("c"); } //编译将打印b // c // a // over } /* 对象的初始化过程 example: Person p = new Person("zhangsan",20); 该句话都做了什么事情? 1.因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中。 2.执行该类中的static代码块,如果有的话,给Person.class类进行初始化。 3.在堆内存中开辟空间,分配内存地址。 4.在堆内存中建立对象的特有属性,并进行默认初始化。 5.对属性进行显示初始化。 6.对对象进行构造代码块初始化。 7.对对象进行对应的构造函数初始化。 8.将内存地址赋给栈内存中的p变量。 */ /* 设计模式 Java中23种设计模式 单例:解决一个类在内存中只存在一个对象 想要保证对象唯一 1.为了避免其他程序过多建立该类对象,先控制禁止其他程序建立该类对象 2.还为了让其他程序可以访问到该类对象只好在本类中,自定义一个对象 3.对外提供自定义对象的访问方法 用代码体现: 1.将构造函数私有化 2.在类中创建本类对象 3.提供一个方法可以获取到该对象 */ //第一种体现方式(先初始化对象):称为俄汉式 class Single { private Single(){} //将构造函数私有化,就是因为类中的默认构造函数,才能new对象,而我们把构造函数私有化,那么就不能new对象了 private static Single s = new Single(); //成员变量最好私有化 public static Single getInstance() { return s; } } class SingleDemo1 { public static void main(String[] args) { Single ss = Single.getInstance(); } } //第二种体现方式(对象是方法被调用时,才初始化):称为对象的延时加载(也叫懒汗式) class Single { private Single(){} private static Single s = null; public static synchronized Single getInstance() //加上synchronized效率会变低,相当于上锁 { if(s==null) s = new Single(); return s; } } class SingleDemo2 { public static void main(String[] args) { Single ss = Single.getInstance(); } } //为了解决上锁效率问题,我们可以利用双重判断来解决 class Single { private Single(){} //将构造函数私有化,就是因为类中的默认构造函数,才能new对象,而我们把构造函数私有化,那么就不能new对象了 private static Single s = null; public static Single getInstance() { if(s==null) { synchronized(Single.class) { if(s==null) s = new Single(); } } return s; } } class SingleDemo3 { public static void main(String[] args) { Single ss = Single.getInstance(); } } //上面的代码懒汉式很复杂,所以定义单例,建议使用饿汉式 /* 继承:将共性描述提取出来,单独进行描述,只要让子类继承父类就可以了 特点: 1.提高了代码的复用性 2.让类与类之间产生了关系,有了这个关系,才有了多态的关系 3.千万不要为了获取其他类的功能,简化代码而继承必须是类与 类之间有所属关系才可以继承,所属关系:(is a //谁是谁的一员,谁是谁的一种) 4.Java只支持单继承,不支持多继承(因为多继承容易带来安全隐患) 但是Java保留这种机制,并用另一种体现形式来完成,多实现 5.Java支持多层继承,也就是一个继承体系 想要使用体系,先查阅体系父类的描述,因为父类中定义的是该 体系的共性功能,通过了解共性功能,就可以知道该体系的基本 功能,那么这个体系可以基本使用了 6.具体调用时,要创建最子类的对象,因为有可能父类不能创建对象 创建子类对象可以使用更多的功能,包括最基本的,也包括特有的 */ class Person //共性的类(父类) { String name; int age; } class Student extends Person //子类继承父类,就有父类的属性了,利用extends关键字 { void study() { System.out.println("good study"); } } class Worker extends Person //子类继承父类,就有父类的属性了,利用extends关键字 { void work() { System.out.println("good work"); } } class ExtendsDemo1 { public static void main(String[] args) { Student stu = new Student(); System.out.println(stu.name); stu.name = "SaMan"; System.out.println(stu.name); } } /* 子父类中变量的特点-super 特点: 1.super关键字,代表父类的引用,super和this的使用几乎一致 this代表本类的引用,super代表父类的引用 */ class Fu { int num = 4; } class Zi extends Fu { int num = 5; //如果子类和父类有相同的变量,结果打印子类自己的 void show() { System.out.println(super.num); //想打印父类的就可以用super关键字,super代表父类的引用 } } class ExtendsDemo2 { public static void main(String[] args) { Zi z = new Zi(); System.out.println(zi.num+"...."+zi.num); z.show(); } } /* 子父类中函数的特点-覆盖(重写) 特点: 1.当子类出现和父类一模一样的函数时,当子类对象调用该函数 会运行子类函数的内容,如同父类的函数被覆盖一样 作用: 当子类继承了父类,沿袭了父类的功能到子类中,子类虽有该功能 但是功能的内容却和父类不一致,这是没有必要定义新功能,而是 使用覆盖的特性保留父类的功能定义并重写功能内容,避免修改以往 的源码,这对程序员来说绝对绝对是一个灾难。此种方法可以有效的 进行后期的功能升级。 注意: 1.子类覆盖父类,必须要保证子类权限大于等于父类权限,才可以覆盖 否则编译失败 2.静态只能覆盖静态 3.重载,只看同名函数的参数列表 重写,子父类方法要一模一样 */ class Fu { void show() { System.out.println("fu show"); } void speak() { System.out.println("vb"); } } class Zi extends Fu { void show() { System.out.println("zi show"); //这里调用z.show()会打印子类的内容 } void speak() { super.speak(); //这里想要使用父类的,可以用super关键字。 System.out.println("Java"); //这里调用z.speak会打印子类的内容,会覆盖父类的内容 } } class ExtendsDemo3 { public static void main(String[] args) { Zi z = new Zi(); z.show(); z.speak(); } } /* 子父类中构造函数的特点 1.在对子类对象进行初始化时,父类的构造函数也会运行,那是因为 子类的构造函数默认第一行有一条隐式的语句 super(); 会访问父 类中空参数的构造函数,而且子类中所有的构造函数默认第一行都 是super();,这里引出一个问题,为什么子类一定要访问父类中的构 造函数? 答:因为父类中的数据,子类可以直接获取,所以子类对象在 建立时,需要先查看父类是如何对这些数据进行初始化的 所以子类在对象初始化时,要先访问一下父类中的构造函 数,如果要访问父类中指定的构造函数,可以通过手动定 义super语句的方式来指定 2.子类的所有的构造函数,默认都会访问父类中空参数的构造函数 因为子类每一个构造函数内的第一行都有一句隐式的super(); 当父类中没有空参数的构造函数时,子类必须手动通过super语句 形式来指定要访问父类中的构造函数,当然,子类的第一行也可以 手动指定this语句来访问本类中的构造函数。子类中至少会有一个 构造函数会访问父类中的构造函数 */ class Fu { Fu() { System.out.println("fu run"); } } class Zi extends Fu { Zi() { //super(); //这句话不写,默认就会存在,super必须卸载第一行,因为你必须先初始化父类 //this(); //this和super只能同时存在一个,二者只能择其一 System.out.println("zi run"); } } class ExtendsDemo4 { public static void main(String[] args) { Zi z = new Zi(); //会打印fu run 和 zi run,原因见上 } } /* final(最终)关键字 特点: 1.final可以修饰类,方法,变量。 2.final修饰的类不可以被继承。为了避免被继承,被子类重写功能 3.final修饰的方法不可以被覆盖 4.final修饰的变量是一个常量,只能被赋值一次 作用:在描述事物时,一些数据的值是固定的,这些值不需要改变,所以 加上final关键字,防止重新赋值,作为常量:常量的书写规范所有 字母都大写,如果由多个单词组成,单词间通过_连接 5.内部类只能访问被final修饰的局部变量。 */ final class Demo //final类不能被继承 { final int x = 3; //final变量只能赋值一次,永远为3 final void show() //final方法不能被重写 { System.out.println("DemoShow"); } } class SubDemo extends Demo //这里不能继承 { void show() //这里不能重写 { System.out.println("SubShow"); } } class FinalDemo1 { public static void main(String[] args) { SubDemo sub = new SubDemo(); } } /* 抽象类(就是Tm让你看不懂!) 当多个类中出现相同功能,但是功能主体不同,这时可以进行向上抽取, 这是只抽取功能定义,而不抽取功能主体。 特点: 1.抽象方法一定要定义在抽象类中。 2.抽象方法和抽象类都必须被abstract关键字修饰 3.抽象类不可以用new创建对象,因为调用抽象方法没意义 4.抽象类中的方法要被使用,必须要由子类重写其所有抽象方法后,建立子类对象调用 如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类 */ abstract class Student //抽象方法,必须创建在抽象类中 { abstract void study();//这里因为不抽取主体,所以可以不用{}结尾,用;结尾 abstract关键字来定义抽象类 } class BaseStudent extends Student { void study() { System.out.println("study"); } } class AbvStudent extends Student { void study() { System.out.println("study"); } } class AbstractDemo1 { public static void main(String[] args) { BaseStudent bstu = new BaseStudent(); AbvStudent astu = new AbvStudent(); } } /* 模板方法设计模式: 在定义功能时,功能的一部分,但是有一部分是不确定的,而确定的部分在使用不确定的部分 那么这是,就将不确定的部分开放出去,由该类的子类去完成 需求:获取一段程序的运行时间 原理:获取时间: System.currentTimeMillis(); */ abstract class GetTime { public final void getTime() //因为此方法,是主要方法,不允许随意重写,所以final { long start = System.currentTimeMillis(); //for(int x=0; x<1000; x++) //把要获取运行时间的代码写在start和end中间 //{ //因为不停的该代码,非常不方便,因此我们可 // System.out.println(x); //以把要获取的代码提去出来,封装成一个功能 //} runcode(); //这里直接调用封装好的代码就可以了 long end = System.currentTimeMillis(); System.out.println("毫秒: " + (end-start)); } public abstract void runcode(); //因为要运行什么什么代码不确定,所以抽象 } class SubTime extends GetTime { public void runcode() //这里重写runcode就可以实现不用每次重写很多代码 { for(int x=0; x<4000; x++) { System.out.println(x); } } } class TemplateDemo1 { public static void main(String[] args) { SubTime stime = new SubTime(); stime.getTime(); } } /* 接口 初期理解:可以理解,可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的 那么该类可以通过接口的方式来表示,class用于定义类,interface用于 定义接口,接口不能创建对象,接口可以被类多实现,也是多继承不支持 的转换形式 接口与接口之间的关系:继承 接口与类之间的关系:实现 类与类之间的关系:继承 接口的特点: 1.接口是对外暴露的规则 2.接口是程序的功能扩展 3.降低了开发的耦合性(模块化式开发) 4.接口可以用来多实现 5.类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口 6.接口与接口之间可以有继承关系 格式: interface {} 接口中的成员修饰符是固定的,都是public的 成员常量: public static final 成员函数: public abstract 接口的出现将"多继承"通过另一种形式体现出来,即"多实现" */ interface Interface1 { public static final int NUM = 3; //全局常量 public abstract void show(); } interface Interface2 { public abstract void method(); } class InterDemo { public void function(){} } class Test extends InterDemo implements Interface1,Interface2 //implements(实现),用于实现接口,而类里面用extends(继承)是因为父类中有直接可以用的方法,而接口全是抽象的,必须全部实现才能使用,一个类,可以继承还可以多继承 { public void show(){} public void method(){} } class InterfaceDemo1 { public static void main(String[] args) { Test t = new Test(); System.out.println(t.NUM); System.out.println(Test.NUM); System.out.println(Interface1.NUM); } } //example: abstract class Student { abstract void study(); void sleep() { System.out.println("sleep"); } } interface Smoking //将不是共性的不确定的方法,定义为接口 { void smoke(); } class ZhangSan extends Student implements Smoking //需要的时候再用 { void study(){} public void smoke(){} } class Lisi extends Student //不需要就可以不调用 { void study(){} } class SmokeDemo1 { public static void main(String[] args) { ZhangSan zs = new ZhangSan(); zs.sleep(); } } /* 多态 定义:某一类事物的多种存在形态, 多态的好处:多态的出现,提高了程序的扩展性 多态的前提:必须是类与类之间有什么关系,要么继承,要么实现,通常还有一个前提:存在覆盖 多态的弊端:虽然提高了扩展性,但是只能使用父类的引用访问父类中的成员 多态的特点:多态中成员函数(指非静态),在编译时期,参阅引用型变量所属类中是否有调用的方法,如果有 在运行时期,参阅对象所属类中是否有调用的方法,在多态中成员变量的特点,无论 编译和运行,都参考左边(引用型变量所属的类)) 简单总结:成员函数在多态调用时,编译看左边,运行看右边 */ //1.多态的体现, abstract class Animal { public abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("啃骨头"); } public void KanJia() { System.out.println("看家"); } } class Pig extends Animal { public void eat() { System.out.println("吃饲料"); } public void gongDi() { System.out.println("拱地"); } } //================================================= class DuoTaiDemo1 { public static void main(String[] args) { function(new Cat()); function(new Dig()); function(new pig()); public static void function(Cat c) { c.eat(); } public static void function(Dog d) { d.eat(); } public static void function(pig p) { p.eat(); } } } /* 以上写法,每次加一个动物,就要加一个方法,很不方便,因为猫狗猪同属与动物类型,所以我们 可以利用父类来引用,因为父类可以接收自己的子类对象,找到了所有类中的共性类型,干脆就操 作它们的共性类型的内容 */ abstract class Animal { public abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("啃骨头"); } public void KanJia() { System.out.println("看家"); } } class Pig extends Animal { public void eat() { System.out.println("吃饲料"); } public void gongDi() { System.out.println("拱地"); } } //================================================= class DuoTaiDemo2 { public static void main(String[] args) { function(new Cat()); function(new Dog()); function(new Pig()); } public static void function(Animal a) { a.eat(); } } /* 多态-转型 */ abstract class Animal { public abstract void eat(); } class Cat extends Animal { public void eat() { System.out.println("吃鱼"); } public void catchMouse() { System.out.println("抓老鼠"); } } class Dog extends Animal { public void eat() { System.out.println("啃骨头"); } public void KanJia() { System.out.println("看家"); } } class Pig extends Animal { public void eat() { System.out.println("吃饲料"); } public void gongDi() { System.out.println("拱地"); } } //================================================= class DuoTaiDemo3 { public static void main(String[] args) { Animal a = new Cat(); //类型提升,向上转型 a.eat(); //如果想操作猫的特有方法时,如何操作? //强制将父类的引用,转换成子类类型,向下转型 if(a instanceof Cat) { Cat c = (Cat)a; c.catchMouse(); //向下转型 } else if(a instanceof Dog) //instanceof 判断实力的引用 { Dog d = (Dog)a; d.KanJia(); //向下转型 } else if(a instanceof Pig) { Pig p = (Pig)a; p.gongDi(); //向下转型 } /* 千万不要出现下面的操作,就是就父类对象转换成子类类型 我们能转换的是父类应用指向了自己的子类对象时,该应用 可以被提升,也可以被强制转换,多态自始自终都是子类对 象在做着变化 Animal a = new Animal(); Cat c = (Cat)a; */ } } /* 多态示例:电脑运行实例,电脑运行基于主板 class MainBoard //主板 { public void run() { System.out.println("mainboard run"); } public void useNetCard(NetCard ncard) //网卡接口 { ncard.open(); ncard.close(); } } class NetCard //网卡 { public void open() { System.out.println("netcard open"); } public void close() { System.out.println("netcard close"); } } 以上方法很不方便,网卡和主板的耦合性太高 利用接口来降低主板和插槽的耦合性 */ interface PCI //PCI插槽 { public void open(); public void close(); } class MainBoard //主板 { public void run() { System.out.println("MainBoard run"); } public void usePCI(PCI p) //PCI插槽 { if(p!=null) //没有插板卡就不运行 { p.open(); p.close(); } } } class NetCard implements PCI //网卡 { public void open() { System.out.println("netcard run"); } public void close() { System.out.println("netcard stop"); } } class SoundCard implements PCI //声卡 { public void open() { System.out.println("soundcard run"); } public void close() { System.out.println("soundcard stop"); } } class DuoTaiDemo4 { public static void main(String[] args) { MainBoard mb = new MainBoard(); mb.run(); mb.usePCI(new NetCard()); //PCI插槽网卡接口 mb.usePCI(new SoundCard()); //PCI插槽声卡接口 } } /* 多态的扩展示例 需求:数据库的操作 1.连接数据库:JDBC Hibernate 2.操作数据库:增删改查 3.关闭数据库连接: */ class UserInfoByJDBC { public void add(User user) { //1.连接数据库 //2.使用SQL语句添加数据 //3.关闭SQL连接 } public void delete(User user) { //1.连接数据库 //2.使用SQL语句删除数据 //3.关闭SQL连接 } public void modify(User user) { //1.连接数据库 //2.使用SQL语句修改数据 //3.关闭SQL连接 } public void find(User user) { //1.连接数据库 //2.使用SQL语句查找数据 //3.关闭SQL连接 } } class DBOperate { public static void main(String[] args) { UserInfoByJDBC ui = new UserInfoByJDBC ui.add(user); ui.delete(user); } } //耦合性态高,用接口来解决 interface UserInfoDAO { public void add(User user); public void delete(User user); } class UserInfoByJDBC implements UserInfoDAO { public void add(User user){} public void delete(User user){} } class UserInfoByHibernate implements UserInfoDAO //下次在添加别的方法,直接在创建该对象的引用即可 { public void add(User user){} public void delete(User user){} } class DBOperate { public static void main(String[] args) { UserInfoDAO ui = new UserInfoByJDBC //UserInfoByHibernate ui = new UserInfoByHibernate ui.add(user); ui.delete(user); } } //object类-equals() 比较的是对象的内存地址 class obDemo1 { private int num; Demo(int num) { this.num = num; } public boolean compare(Demo d) { return this.num==d.num; } } class objectDemo1 { public static void main(String[] args) { obDemo1 ob1 = new obDemo1(); obDemo1 ob2 = new obDemo1(); obDemo1 ob3 = ob1; System.out.println(ob1.equals(ob2)); //false 对象不同,就为false,因为比较的是内存地址 System.out.println(ob1.equals(ob3)); //true System.out.println(d1==d2); //false System.out.println(d1==d3); //true } } //如果想要比较,obDemo1中的变量怎么做呢? class obDemo2 { private int num; obDemo1(int num) { this.num = num; } public boolean compare(obDemo1 d) { return this.num==d.num; } } class objectDemo2 { public static void main(String[] args) { obDemo1 ob1 = new obDemo1(4); obDemo1 ob2 = new obDemo1(6); System.out.println(ob1.compare(4)); //false 对象不同,数据相同也为true 这里就不再是比较内存地址了,这里引出一个问题,明明父类提供了equals方法为什么还要重新定义呢? 只要沿袭父类功能建立自己特有的比较内容即可 } } // class obDemo3 { private int num; obDemo3(int num) { this.num = num; } public boolean equals(Object obj) //这里要向下转型,因为num在object类中没有定义 { if(!(obj instanceof Demo)) //如果不是同类型的类,直接返回false return false; obDemo3 d = (obDemo3)obj; return this.num == d.num; } } class Person{} class objectDemo3 { public static void main(String[] args) { obDemo3 ob1 = new obDemo3(4); obDemo3 ob2 = new obDemo3(4); //Person p = new Person(); System.out.println(ob1.equals(ob2)); //System.out.println(ob1.equals(p)); //这里编译不会报错,运行会报错,因为比较类型不一样 } } //object类-toString() class obDemo4{} class objectDemo4 { public static void main(String[] args) { obDemo4 ob1 = new obDemo4(); System.out.println(ob1.toString()); //返回obDemo4@c2391 @前表示object运行时的类@后表示对象的hash值 } } //object类-hashCode() class obDemo5{} class objectDemo5 { public static void main(String[] args) { obDemo5 ob1 = new obDemo5(); System.out.println(ob1.hashCode()); //返回object运行时的hash值 } } //object类-getClass() class obDemo6{} class objectDemo6 { public static void main(String[] args) { obDemo6 ob1 = new obDemo6(); Class c = ob1.getClass(); //获取class文件 System.out.println(c.getName()); //获取class文件的实体 } } /* 内部类:将一个类定义在另一个类里面,对里面那个类就称为内部类(内置类,嵌套类) 访问特点:内部类可以直接访问外部类中的成员,包括私有成员,而外部类要访问内部类中的成员必须要建立内部类的对象 */ class Outer1 { int x = 3; void method() { Inner1 in = new Inner1(); in.function(); } class Inner1 //内部类,内部类可以直接访问外部类中的变量或方法 { int x = 4; void function() { int x = 6; System.out.println("inner :"+Outer1.this.x); //想要打印外部类中的x,用外部类名+this,这就是内部类能直接访问外部类的原因,前面省略了外部类名.this } } } class InnerClassDemo1 { public static void main(String[] args) { Outer1 out = new Outer1(); out.method(); //直接访问内部类中的成员 //Outer1.Inner1 in = new Outer1().new Inner(); //in.function(); } } /* 静态内部类: */ class Outer2 { private int x = 3; static class Inner2 //静态内部类,当内部类被静态修饰后,只能直接访问外部类中的静态成员 { void function() { System.out.println("inner :"+x); } } } class InnerClassDemo2 { public static void main(String[] args) { //这里会报错,因为静态类不能访问非静态数据 new Outer2.Innter2().function(); //直接访问静态内部类中的方法 } } /* 内部类定义原则 当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容 */ /* 匿名内部类 匿名内部类其实就是内部类的简写格式 定义匿名内部类的前提: 1.内部类必须是继承一个类或者实现接口 匿名内部类的格式: new 父类或者接口(){定义子类内容} 其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖,可以理解为带内容的对象 匿名内部类中定义的方法最好不要超过3个 */ class Inter { void method(); } class Test { //需求,补足代码,通过匿名内部类 /* //内部类形式 static class Inner implements Inter { public void method() { System.out.pritln("method run") } } */ static Inter function() { //return new Inner(); return new Inter() { public void method() { System.out.pritln("method run") } } } } class InnerClassTest { public static void main(String[] args) { Test.function().method(); //Test.function():Test类中有一个静态的方法function //.method():function方法中运算后的结果是一个对象,而且是一个Inter类型的对象 //因为只有是Inter类型的对象,才可以调用method方法 } } /* 异常,异常就是程序运行时出现不正常的情况 异常由来:问题也是现实生活中的一个具体的事物,也可以通过java的类形式进行描述,并封装成对象。 其实就是java对不正常情况进行描述后的对象的体现。 对于问题的划分: 1.严重问题:java通过Error类进行描述,对于Error一般不编写针对性代码对其进行处理 2.非严重问题:java通过Exception类进行描述,对于Exception可以使用针对性的处理方式进行处理 无论Error或者Exception都具有一些共性内容 比如:不正常情况的信息,引发原因等 Throwable |--Error //严重性疾病 |--Exception //一般性疾病 异常的处理:java提供了特有的语句进行处理 try { 需要被检测的代码 } catch(异常类 变量) { 处理异常的代码(处理方式) } finally { 一定会执行的语句 } 对捕获到的异常对象进行常见方法操作 String getMessage() //获取异常的信息 String toString() //打印异常描述 void printStackTrace() //打印堆栈中的跟踪信息 */ class Throwable { int div(int a,int b) { return a/b; } } class ExceptionDemo1 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(4,0); System.out.println("x="+x); } catch(Exception e) { System.out.println("除零了"); System.out.println(e.getMessage()); //打印异常信息 System.out.println(e.toString()); //打印异常描述 e.printStackTrace(); //打印堆栈中的跟踪信息 } System.out.println("over"); } } //异常声明throws class Throwable { int div(int a,int b)throws Exception //在功能上通过throws声明该功能有可能会出现问题 { return a/b; } } class ExceptionDemo2 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(4,0); System.out.println("x="+x); } catch(Exception e) { System.out.println("除零了"); System.out.println(e.getMessage()); //打印异常信息 System.out.println(e.toString()); //打印异常描述 e.printStackTrace(); //打印堆栈中的跟踪信息 } System.out.println("over"); } } /* 对多异常的处理 1.声明异常时,建议声明更为具体的异常,这样处理的可以更具体。 2.对方声明几个异常就对应有几个catch块,进行针对性处理,如果 多个catch块中的异常出现继承关系,父类异常catch块放在最下边。 不要定义多余的catch块 3.建议在进行catch处理时,catch中一定要定义具体的处理方式。不要 简单的定义一句e.printStackTrace(),也不要简单的就书写一条输出语句 */ class Throwable { int div(int a,int b)throws ArithmeticException,ArrayIndexOutOfBoundsException //声明算术异常,这里处理抛出的异常更具体 { int[] arr = new int[a]; System.out.println(arr[4]); return a/b; } } class ExceptionDemo3 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(5,0); //函数中只要有异常发生,如果没有处理的话,程序就结束了 System.out.println("x="+x); } catch(ArithmeticException e) { System.out.println(e.toString()); //打印异常描述 System.out.println("除零了"); } catch(ArrayIndexOutOfBoundsException e) { System.out.println(e.toString()); //打印异常描述 System.out.println("角标越界"); } catch(Exception e) //有继承关系的,父类放在下面 { System.out.println("异常了"); } System.out.println("over"); } } /* 自定义异常 因为项目中会出现特有的问题,而这些问题并未被java所描述并封装对象 所以对这些特有的问题,可以按照java对问题封装的思想,将特有的问题 进行自定义异常封装 需求: 在本程序中对于除数是负数也视为异常,那么就需要对这个问题进行自定义的描述 当函数内部出现了throw抛出异常对象,那么就必须要给出对应的处理动作 要么在内部try catch处理,要么在函数上声明,让调用者处理 一般情况下函数内出现异常,函数上需要声明 自定义异常:必须是自定义类继承Exception 为什么要继承Exception呢? 答: 异常体系有一个特点,因为异常类和异常对象都需要被抛出,它们都具备可抛性 这个可抛性是throwable这个体系中的独有特点,只有这个体系中的类和对象才可 以被throws和throw操作 throws和throw的区别: 1.throws使用在函数上,throw使用在函数内 2.throws后面跟的是异常类,可以跟多个,用逗号隔开 3.throw后面跟的是异常对象 */ class FuShuException extends Exception //加入Exception体系 { } class Throwable { int div(int a,int b)throws FuShuException //一般情况下函数内出现异常,函数上需要声明 { if(b<0) throw new FuShuException(); //手动通过throw关键字抛出一个自定义异常对象 return a/b; } } class ExceptionDemo4 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(4,-1); System.out.println("x="+x); } catch(FuShuException e) { System.out.println(e.toString()); //发现打印的结果只有异常的名称,没有异常信息,因为自定义异常没有定义信息 System.out.println("除数出现负数了"); } System.out.println("over"); } } //如何定义信息呢? class FuShuException extends Exception //加入Exception体系 { /* 这样写太复杂 private String msg; FuShuException(String msg) { this.msg = msg; } public String getMessage() { return msg; } */ FuShuException(String msg) { super(msg); //因为父类中已经把异常信息操作都完成了,所以子类只要在构造时,将异常信息传递给父类通过super语句。那么就可以直接通过getMessage方法获取自定义异常信息了 } } class Throwable { int div(int a,int b)throws FuShuException { if(b<0) throw new FuShuException("出现了除数是负数的情况/ by fushu"); return a/b; } } class ExceptionDemo5 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(4,-1); System.out.println("x="+x); } catch(FuShuException e) { System.out.println(e.toString()); System.out.println("除数出现负数了"); } System.out.println("over"); } } /* RuntimeException(运行时异常) RuntimeException或它的子类,如果在函数内抛出了,函数上不用声明 之所以不用在函数上声明,是因为不需要让调用者处理,当该异常发生,希望程序停止 因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正 如果在函数上声明了该异常,调用者可以不用进行处理,编译一样通过 自定义异常时,如果该异常的发声,无法在继续进行运算,就让自定义异常继承RuntimeException 对于异常分两种: 1.编译时被检测的异常 2.编译时不被检测的异常(运行时异常,RuntimeException以及其子类) */ class FuShuException extends RuntimeException //自定义类让程序一旦发生该异常就停止运行,可以继承RuntimeException { FuShuException(String msg) { super(msg); } } class Throwable { int div(int a,int b)//throws ArithmeticException 这里不用声明 { if(b<0) throw new FuShuException("除数不能为负数"); //这里抛出继承RuntimeException的异常就可以了,如果非RuntimeException异常,那么必须在函数上声明 if(b==0) throw new ArithmeticException("被零除啦"); //一旦抛出runtime异常,表示不希望调用者处理,直接让程序停止,调用者必须修改代码,程序才能正常运行 return a/b; } } class ExceptionDemo6 { public static void main(String[] args) { Throwable t = new Throwable(); int x = t.div(4,-1); System.out.println("x="+x); } } /* 异常finally:定义一定要执行的代码,通常用于关闭资源 */ class FuShuException extends Exception { FuShuException(String msg) { super(msg); } } class Throwable { int div(int a,int b)throws FuShuException { if(b<0) throw new FuShuException("除数为负数"); return a/b; } } class ExceptionDemo7 { public static void main(String[] args) { Throwable t = new Throwable(); try { int x = t.div(4,-1); System.out.println("x="+x); } catch(FuShuException e) { System.out.println(e.toString()); return; //这里结束函数,最下面的不执行,但是finally里面的一定会执行 } finally { System.out.println("finally"); //finally中存放的是一定会被执行的代码 } System.out.println("over"); } } /* 异常-处理语句其他格式 格式1: try { } catch() { } 格式2: try { } catch() { } finally { } 格式3: try { } finally { } 记住一点:catch是用于处理异常,如果没有catch就代表异常没有被处理 如果该异常是检测时异常那么必须要声明 */ /* 异常-在覆盖时的特点 1.子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法 只能抛出父类的异常或者该异常的子类 2.如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集 3.如果父类或者接口的方法中,没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常 如果子类方法发生了异常,就必须要进行try处理,绝对不能抛。 */ /* Exception |--AException |--BException |--CException */ class AException extends Exception { } class BException extends AException { } class CException extends Exception { } class Fu { void show()throws AException //子类在覆盖父类时,如果父类的方法抛出异常 { } } class Zi extends Fu { void show()throws AException //那么子类的覆盖方法只能抛出父类的异常或者该异常的子类 { } } /* package(包) 对类文件进行分类管理 给类提供多层命名空间 写在程序文件的第一行 类名的全称是包名.类名 包也是一种封住形式 */ package pack; //定义包,包名要全小写 class Demo1 { public static void main(String[] args) { //编译的时候加参数让编译器自动生成包目录 javac -d System.out.println("Hello Package"); //引用的时候 java pack.Demo1 } } /* 包与包之间的访问 问题:不同包之间的类该如何访问呢? 包中的类一样存在继承关系 总结:包与包之间进行访问,被访问的包中的类以及类中的成员,需要public修饰 */ package pack1; //这里建立一个包 class Demo1 { public static void main(String[] args) { pack2.demo1 p2demo1 = new pack2.Demo1(); //要调用必须把包名写全 p2demo1.show(); } } package pack2; //这里建立一个包 public class Demo1 //无法从外部软件包对其进行访问,必须权限要加public { public void Show() //类公有后被访问的成员也要公有 { System.out.println("packDemo1 show run"); } } /* protected(保护)权限 不同包中的子类,还可以直接访问父类中被protected权限修饰的成员 包与包之间可以使用的权限只有2种 public protected 权限大小顺序 1.public 2.protected 3.default 4.private 访问权限问题: public protected default private 同一个类 ok ok ok ok 同一个包 ok ok ok no 子类中 ok ok no no 不同包中 ok no no no */ package pack3; public class Demo1 extends pack4.Demo1 //包中的类也存在继承关系 { public void show() { method(); //这里可以直接访问,因为它继承了pack4.Demo1 } } package pack4; public class Demo1 { protected void method() //给此方法加保护权限, { System.out.println("pack4.packDemo1.method is run..."); } } package main; class MainDemo3 { public static void main(String[] args) { //pack3.Demo1 p3demo1 = new pack3.Demo1(); //p3demo1.show(); //pack4.Demo1 p4demo4 = new pack4.Demo1(); //这里就不能在直接访问了,因为method()方法保护了,只能在本类,或子类中访问 //p4demo1.method(); //要想访问,必须继承pack4.Demo1才可以 } } /* 导入import 为了简化类名的书写,使用import关键字(in母泡特) import导入的是包中的类,其他东西一概不导入 建议不要写通配符*,一般用那个类,导哪个类,否则浪费内存空间 导入不同包中的类中如果有重名的类,这个类必须加包名 定义包名为了不重复,建议使用url来完成定义,因为url是唯一的 example: www.itcast.cn package cn.itcast.demo //此种方式定义包名比较靠谱 package cn.itcast.test */ import pack4.Demo1; //导入pack4包的Demo1类