1.1什么是对象
车是对象、人是对象、电脑是对象,登录、注册、删除商品、购物车在Java中万事万物皆为对象。 解决实际问题的时候,能够正确的创建对象,并且需要能够正确的找对对象。
1.2对象和类的关系
类:
-
种类,动物类,人类,类别
-
为了满足人类更好的认识周边这个社会,我们将某些具备相同特征的动物,其他的东西归为一类
-
归类的方式:将具备相同表现或者是相同功能的某些具体事务放置在一起归为一类
-
-
抽象的概念:构想去了多个具体的事务的像的部分归为一类
对象
-
丹顶鹤、啄木鸟等等这些就是对象,现实生活中看得见的。摸得着都是对象。
-
通过类具象化、实例化出来的内容对象。
先有类还是先有对象?
-
构建角度: 先有类才有对象。 先存在类 对象才能被实例化出来
-
编码角度:先有对象才有类。 先有对象 类才能被创建出来
1.3类和对象的编写
1,类:人类(学生类) 2,张三,李四,王五
3,外在的表现形式:变量 姓名,年龄,性别 ---> 成员变量 4,内在的功能:方法 吃饭 睡觉 打豆豆 ---> 成员方法[非static修饰的方法]
1.3.1编写类
public class Person { /* 外在的表现形式 属性、字段、域 */ String name; // 姓名 int age; boolean gender; /* 内在的功能 */ public void eat(){ System.out.println("我在吃饭"); } public void sleep(){ System.out.println("我在睡觉"); } }
1.3.2测试代码
public static void main(String[] args) { System.out.println("hello idea"); // 创建person对象 Person p1 = new Person(); // 给名字 p1.name = "张三"; p1.age = 0; p1.gender = false; System.out.println(p1.name); }
1.4构造器
1,构造创建对象的机器,就是一个方法;这个方法通过new关键词可以创建出来,当前的类的实例对象
2,这个方法很特殊:v
-
不存在返回值(不能显式的在构造器中编写return语句)
-
方法名称和当前类的名称一致
-
一个类默认为存在一个空参数的构造器;方便用户调用之后创建该类的实例对象,如果你在当前类中顶定义了其他的构造器;此时默认的空构造器就不存在了【我们要有意识写一个空构造器】
-
构造器允许重载
-
public class Class06_Person { public static void main(String[] args) { Person person = new Person("小明",175,130,20); person.function(); } } //定义一个人类 class Person{ //名字 public String name; //身高 public double height; //体重 public double weight; //年龄 public int age; //定义一个空构造 public Person(){ } //定义一个带参构造 public Person(String Aname,double Aheight,double Aweight,int Aage){ name = Aname; height = Aheight; weight = Aweight; age = Aage; } //定义一个功能 public void function(){ System.out.println(name+"的身高是"+height+"体重是"+weight+"年龄是"+age); } }
-
1.5this的使用
1,编写代码的时候,我们区理解带参构造器
public Person(String pname){ //"李四" name = pname; }
将通过带参构造器创建person对象时;传入的李四作为参数,将其赋值给p2对象的成员变量name
2,this.代表的是当前对象的
3,this . 不可以省略;局部变量和成员变量在同名的情况下,此时需要通过this来代表对象的属性(对象的成员变量)
// 带参数的构造器 public Person(String name){ //"李四" this.name = name; // 局部变量name 赋值给p2对象的成员变量name }
4,this.可以省略
/* 内在的功能 */ public void eat(){ System.out.println(this.name+"在吃饭"); }
5,this的使用
-
对于构造器而言,如果需要进行互相调用,必须要使用this()
-
在使用this()的时候必须要正这行语句在当前构造器的首行
1.6static
1,static的使用
-
static:静态的,共享的,独一份
package com.yjxxt.oop.basic; public class Test03 { int num = 3; static String str = "zhangsan"; public static void main(String[] args) { Test03 test03 = new Test03(); System.out.println(test03.num); test03.method(); System.out.println(Test03.str); System.out.println(test03.str); // idea工具不推荐按照这种对象引用的方式去访问静态内容 } public void method(){ System.out.println("我是非静态方法"+num); System.out.println(Test03.str); } }
-
静态调用非静态 创建非静态所属类的对象 通过对象 .
-
静态调用静态;直接调用
-
非静态调用静态 通过类名直接调用
-
非静态调用非静态;直接调用
2, static的内部实现机制
-
static 修饰的内容隶属于类,而且在类加载的时候,会被加载到内存,并且只有一份
-
非static修饰的内容隶属于对象,对象存在,他才能存在
-
静态内容先于对象存在
1.7block块
1, block 块 {} : 自成作用域 分类: 执行时机: {}定义在方法中|语句块中 --> 局部代码块 跟随方法的调用 {}定义在类中方法外 ---> 构造块 跟随new一起使用 static{}定义在类中方法外--> 静态块 类第一次 同步块
2,构造块中的代码会先于构造器中的代码之前执行,在编译期间构造块中的代码会被编译到要执行的构造器代码的最上面 如果存在多个构造块,从上到下一次执行 静态块会在类第一次加载完成之后进行执行,并且只执行一次 如果存在多个静态块,从上到下一次执行 构造块作用 : 为成员提供默认初始化 静态块作用 : 1)为静态内容提供默认的初始 2) 基础设置等的加载(数据库的驱动...)
public class Class01_block { static int anInt; String name; //定义静态块 static { anInt = 2; System.out.println("我是静态块1----->"+anInt); } static { System.out.println("我是静态块2"); } static { System.out.println("我是静态块3"); } //定义构造块 { name="小明"; System.out.println("我是构造块1---->"); System.out.println("我的名字是"+name); } { name="小刚"; System.out.println("我是构造块2"); System.out.println("我的名字是"+name); } //定义构造器 public Class01_block(){ System.out.println(); } public Class01_block(String name){ this.name=name; System.out.println("我是构造器"); } public static void main(String[] args) { int i = 5; //定义局部块 { //i = 2; System.out.println("我是局部块"); } System.out.println(i); System.out.println(new Class01_block("小刚").name); } }
1.8Dubug调试工具
作用:1.追踪程序的执行流程 2.定位异常出现的位置 3.观察程序执行过程中变量的变化情况 4.根据追踪程序的执行流程学习第三方框架的源码
步骤:1.设置断点 在行号的后面鼠标单击设置断点 2.Debug运行 3.debug运行模式下进行调试 Step over F8 : 下一步跳过|略过 如果下一步是方法的调用,不会跟随方法的调用执行,直接进入下一步 Step into F7 : 步入 | 下一步进入 如果下一步是自定义方法的调用,跟随方法的调用执行每一步 Step out shift+f8 : 下一步调出 如果在方法的内部,下一步直接调出到方法调用处 Force step into alt+shift+f7 : 下一步强制进入 如果下一步是方法的调用,包括jdk源码方法的调用,强制进入,跟随执行 Run to Cursor alt+F9 : 直接运行到鼠标光标所在位置
1.9package与import
package: 包机制: 文件夹 帮助管理众多的资源 提供了多重命名空间 包信息: 存在与java文件的最上面首行,标识当前类型所在的包路径
import: 导包: 指明要使用类型的位置 如果要使用其它类型,可能涉及到导包问题 不需要导包的类: 1)java.lang包下的内容 2)同包类 导包的方式: 1.使用的位置指定类型的全限定名 : 包名.类名 只能在当前位置使用一次,简单方便,但是使用频繁的话建议使用import导包 2.import关键字进行导包 定义语法 : import 包名.类名; 位置: 类的上面,package信息下面 3.模糊匹配 模糊匹配当前报下要使用的所有类型 只会降低编译效率,不会降低运行效率 4.静态导入 import static 导入一个类型中的静态内容 注意: 以后项目中需要先定义包后定义类型
public class Class001_Package { public static void main(String[] args) { java.util.Scanner sc = new java.util.Scanner(System.in); Scanner sc2 = new Scanner(System.in); Random ran = new Random(); ArrayList list = new ArrayList(); System.out.println(PI); System.out.println(PI); System.out.println(PI); System.out.println(PI); System.out.println(round(1.4)); System.out.println(round(1.4)); System.out.println(round(1.4)); } }
2.0封装
1, 面向对象的三大特性: 封装 继承 多态 封装: 隐藏内部的实现细节,对外提供公共的访问方式 优点: 提高安全性 提高代码的复用性 问题: 私有是封装,是封装一个具体的体现 封装不仅仅是私有,类,方法,属性私有化... JavaBean : 代表一系列的实体类|模板类 规范: 1.类是公共的 2.至少提供一个空构造 3.属性私有化 4.提供一对公共的访问方式
2, 数据的安全隐患问题 解决 : private 私有的 private 私有的,成员修饰符(只能修饰成员不能修饰局部) 一旦被private关键字修饰的成员只能在当前类中使用 私有的属性需要配合一对公共的访问方式 设置器 setter : 成员方法,为私有属性设置值 访问器 getter : 成员方法,获取私有属性的值 注意: 以后定义的实体类要求属性全部私有化,并根据需求提供一对公共的访问方式
ublic class Class01_Private { public static void main(String[] args) { //创建一个对象 Person1 person1 = new Person1("陈总",20,"男"); person1.setAge(18); person1.setName("陈总"); person1.setSex("女"); person1.info(); System.out.println(person1.getSex()); } } //创建一个人类 class Person1{ private String name; private int age; private String sex; //创建一个空构造 public Person1(){} //创建一个带参构造 public Person1(String name,int age,String sex){ this.name=name; this.age=age; this.sex=sex; } //创建一个设置器 public void setName(String name){ this.name=name; } //设置访问器 public String getName(){ return name; } public void setAge(int age){ this.age=age; } public int getAge(){ return age; } public void setSex(String sex){ this.sex=sex; } public String getSex(){ return sex; } //设置一个功能 public void info(){ System.out.println(name+"----->"+age+"----->"+sex); } }
2.1继承
1.什么是继承
子承父业
2.如何编写继承关系
继承就是在java中用来描述类和类之间的关系,Java语言只支持单继承,一类子类只能存在一个父类
public class Person { /* 属性 */ String name; int age; boolean gender; public Person(){ } public void sleep(){ System.out.println("睡觉中。。。。。。"); } public void info(){ System.out.println(name+"---"+age+"---"+(gender?"男":"女")); } } public class Teacher extends Person{ int money; /* 构造器 */ public Teacher(){ } public Teacher(String name){ this.name = name; } /* 方法 */ public void teaching(){ System.out.println("上课。。。。。"); } }
-
继承的格式:class A extend B(){ }
-
继承的关系可以提高代码的复用性,但是java只支持单继承,导致在java中复用性提升的有限
-
在实际开发中其实很少会使用继承关系,核心原因还是由于java是单继承的。如果出现必须要继承的时候,后期业务一旦扩展,可以通过如下关系进行:
-
A-B A->B->c 但是这样的关系最多维护三层
-
推荐使用依赖关系,依赖关系的优先级高于继承
-
2.2权限修饰符
1, 权限修饰符 : 访问权限修饰符 本类 同包类 不同包类下的子类 不同包下的其他类 public 公共的 √ √ √ √ protected 受保护的 √ √ √ default 默认的 √ √ private 私有的 √
成员修饰符,只能修饰成员不能修饰局部的 能够修饰类的: public default 父类中被protected修饰的成员,在不同包下的子类中通过继承关系可以使用 常用的: public private
2.3Super的使用方式
-
super ( )
-
创建子类对象的时候,默认情况下在子类的构造器中第一行会存在super()调用父类的构造器,子类对象创建时必须要保证父类被加载
-
super()和this()都只能是编写在构造器中,并且都必须要在首行
-
当出现this() 和super 都必须要出现的场景是,此时一定是省略super()不能省略this
-
-
super.
-
不可省略的地方 就是为了避免(父类和子类出现了同名变量和方法)
-
剩下的都是可省略的。(省略的位置既可以时this也可以时super 为了统一一般我们称其为省 略this)
-
public class Class01_Super { public static void main(String[] args) { Zi zi = new Zi(19); zi.test(); } } //创建一个父类 class Fu{ int age = 10; String name = "父亲" ; //空构造 public Fu(){ System.out.println("父类空构造"); } //带参构造 public Fu(int age){ System.out.println("一个带参构造"); this.age=age; } public Fu(String name){ System.out.println("小明一个带参构造"); } public Fu(int age,String name){ System.out.println("两个带参构造"); } } //创建子类 class Zi extends Fu{ String name = "儿子"; //空构造 public Zi(){ System.out.println("子类空构造"); } public Zi(int age){ super(age); System.out.println("子类带参构造"); } public void test(){ String name = "局部名字"; System.out.println(name);//局部就近原则 System.out.println(this.name);//当前对象成员 System.out.println(super.name);//父类对象成员 System.out.println(age); } }
2.4重写
在父类中定义的某些方法,子类发现不满足自己的需求,此时就会重写,为了保证子类中该方法是重写方法:
-
必须要发生继承关系
-
必须要保证同名 ,保证声明所有内容要一模一样
-
如果实在拿不准自己编写的方法是否重写了父类的方法时,此时可以在子类重写方法上编写 @Override ,如果不报错就是重写了
-
将重写理解为覆盖,覆盖了父类中的方法
-
检查是否为重写方法: 1.在行号的后面存在O重写标识 2.@Override 强制检测方法为重写方法 重写的满足的三个细节条件: == 方法签名 <= 返回值类型 如果返回值类型为基本数据类型|void,要求完全相等 如果返回值类型为引用数据类型 : 要求子类中的重写方法返回值类型<=父类中被重写方法的返回值类型 >= 权限修饰符 子类中重写方法的权限修饰符>=父类中被重写方法的权限修饰符
-
不能被重写的方法: 被private修饰的方法不能被重写,被private修饰的成员可以被继承,但是无权限访问 被final修饰的方法不能被重写 被static修饰的方法不能被重写 如果子类中存在与父类静态方法同名的方法,要求子类中的同名方法也为static才可 方法签名: 是方法的唯一标识 方法名+参数列表
public class Class01_Override { public static void main(String[] args) { SiCong siCong = new SiCong(); siCong.test(); new JiangLin().test(); } } //创建一个父类 class JiangLin{ String name = "王建林"; public void test(){ System.out.println("定一个小目标,先挣一个亿"); } } //创建一个子类 class SiCong extends JiangLin{ String name = "王思聪"; @Override public void test(){ System.out.println("我不在乎别人有没有钱反正我有钱"); } }
2.5final
1,final最终的,成员修饰符
2,被final修饰的类不可被继承
3,被final修饰的变量为常量
4,被final修饰的方法不能被重写
注意: 基本数据类型的变量=右边为数据值 引用数据类型的变量=对象,对象的地址值
public class Class001_Final { //成员 static final Person P = new Person(); static final int I = 1; static final String NAME = ""; public static void main(String[] args) { //1) P = new Person();//对象的地址值改变了 //2) P.age++; } } class Person{ String name; int age; }
2.6Object
1,Object 老祖宗 java.lang.Object 是java中所有类的父类 一个类如果没有显示的继承其他父类,就会默认的继承自Object java中所有类都会显示或者隐式的继承自Object Object类中定义的成员是所有子类,子类对象都可以使用的(不考虑权限修饰符问题)
2,Object类中常用的方法: toString : 返回对象的字符串表现形式 在打印一个对象的引用时,默认输出为当前对象的toString方法的返回值 public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
3, equals : 比较两个对象是否相等 == : 比较是否相等 比较基本数据类型数据值是否相等 比较引用数据类型的地址值是否相等
Object类中的equals的实现: 默认比较对象的地址值 public boolean equals(Object obj) { return (this == obj); }
4, == 与 equals 之间的区别 ==可以比较基本数据类型|引用数据类型,比对象地址 equals默认Object类中比较对象地址,因为内部通过==实现比较 可以通过在子类中重写equals实现比较对象内容
-
clone() :克隆模式一般可以实现Cloneable结合使用
-
finalize():GC垃圾回收器,回收时需要调用方法
-
hashcode():获取当前对象的hash值
-
getClass():获取某个指定类的对应的Class对象
-
toString():获取当前对象的内容
-
equals():比较两个对象是否相等
-
wait、notify、notifyAll在多线程中会使用的
5,javabean规范: 1.类是公共的 2.至少提供一个空构造 3.私有的属性 4.公共的访问方式 5.重写toString与equals方法
public class Class01_Object extends Object{ public static void main(String[] args) { Dog dog1 = new Dog("小黑","9","黑色"); Dog dog2 = new Dog("小黑","9","黑色"); System.out.println(dog1); System.out.println(new Class01_Object().toString()); System.out.println(dog1); System.out.println(dog1==dog2); System.out.println(dog1.equals(dog2)); } } //定义一个狗类 class Dog{ private String name; private String age; private String color; //创建一个带参构造器 public Dog(String name,String age,String color){ this.age=age; this.name=name; this.color=color; } @Override public String toString(){ return this.name+"---->"+age+"---->"+color; } //重写equals方法 public boolean equals(Object obj){ //this第一个对象,obj第二个对象 if (this==obj){ return true; } //判断参数引用是否指向Dog类型对象,是返回true,不是返回false if (obj instanceof Dog){ //多态 向下转型 Dog dog = (Dog) obj; //字符串比较是否相等,需要通过equals比较字符串的内容 if ((this.age).equals(dog.age)&&(this.name).equals(dog.name)&&(this.color).equals(dog.color)){ return true; } } return false; } }
2.7多态
2.7.1测试多态
多态:多种形态 一个对象对外表现状态会发生改变,此时成为多态
2.7.2构成多态的前提:
-
发生继承关系
-
父类引用指向子类对象
-
通过父类变量调用子类重写方法
1, 注意: 正常的情况都应该为对应类型的数据赋值给对应类型的变量,除了当前满足多态时候,才能够实现对应类型的数据赋值给了其他类型的引用 要求其他类型必须为对象的父类类型 2, 多态调用成员的特点: 成员变量: --> 不存在多态 编译运行看父类 编译运行看左边 编译运行看类型 成员方法: --> 行为才有多态 编译看父类,运行 编译看类型 编译看左边 3,多态如果不配合方法的重写,多态没有意义 4, 父类引用指向不同的子类对象,当子类中存在重写,对功能实现方式可能不同,这是行为多态的体现,同一个功能的不同实现方式
public class Class01_Poly { public static void main(String[] args) { //对应类型数据的赋值给对应类型的变量 Person p1 = new Student1(); p1.test(); } } class Person{ int age = 20; String name = "小明"; String sex = "男"; public void test(){ System.out.println("小明"); } } class Student1 extends Person{ int age = 10; String name = "小红"; String sex = "女"; /*public void test(){ System.out.println("小红"); }*/ } class Teacher extends Person{ int age = 18; String sex = "男"; String name = "小刚"; /*public void test(){ System.out.println("小刚"); }*/ }
2.7.3转型:类型转换
1,向上转型 : 孔子决定化妆,装成孔子爹的样子去讲课 KongZiDie zi = new KongZi(); 多态 zi.teach(); 子类中重写的方法
2, 向下转型 : 父类引用 转为对应的子类类型 KongZi z = (KongZi)zi; //KongZi z = new KongZi(); z.play();
3, ClassCastException : 类型转换异常,在向下转型时候转为非其他子类类型 -> Brother z = new KongZi();
4,instanceof 运算符 : 避免在转型的时候遇到类型转换异常的出现,在转型之前先判断 引用 instanceof 类型 判断前面的引用是否是指向后面类型的对象|子类对象 如果是返回true,不是返回false
public class Class001_Cast { public static void main(String[] args) { int i = 1; long l = i; //自动类型提升 int i2 = (int)l; //强制类型转换 //多态 向上转型 KongZiDie d = new Brother(); d.teach(); //向下转型 if(d instanceof Brother){ Brother z = (Brother)d; //Brother z = new KongZi(); z.play(); z.teach(); }else if(d instanceof KongZi){ KongZi z = (KongZi) d; z.play(); z.teach(); } System.out.println(d instanceof KongZiDie); //true System.out.println(d instanceof KongZi); //false System.out.println(d instanceof Brother); //true System.out.println(d instanceof Object); //true System.out.println("main结束了"); } } class KongZiDie{ void teach(){ System.out.println("做生意...."); } } class KongZi extends KongZiDie{ void teach(){ System.out.println("论语...."); } void play(){ System.out.println("LOL..."); } } class Brother extends KongZiDie{ void teach(){ System.out.println("敲代码...."); } void play(){ System.out.println("绝地求生..."); } }
2.8抽象类
1, 抽象类: abstract抽象的 被abstract修饰的类 -->抽象类 被abstract修饰的方法 -->抽象方法 没有方法体 抽象方法必须定义与抽象类中
2, 注意: 1.抽象类不能实例化 2.抽象类中可以定义抽象方法,可以定义非抽象方法,属性,构造器... 3.抽象方法必须定义与抽象类中 4.抽象类的使用: 通过具体子类对象调用 具体子类 : 重写所有的抽象方法 + 按需新增 抽象子类 : 按需重写抽象方法 + 按需新增 5.一个抽象方法如果一旦被重写,后续的子类中可以不再重写,可以按需重写 6.抽象方法必须要被重写,没有重写,没有方法体,不能调用 7.abstract不能与static,private,final与native一起使用
-
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
-
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类
-
类本省就是对于对象的抽象,抽象类就是比类还要抽象的类。
通过abstract修饰的类称之为抽象类:
-
专门给子类继承用的
-
可以编写构造器,但不能参加对象,他的构造器是用来给子类创建对象,因为子类创建对象的时候需要调用父类构造器
-
可以编写普通方法,也可以创建抽象方法
-
通过abstract修饰的方法称为抽象方法,抽象方法只有声明,没有方法体
-
子类继承了抽象类之后必须要重写父类中所有的抽象方法
-
-
关于抽象类而言,在一定程度上确保了子类设计的随意性
声明抽象方法会造成以下两个结果:
1.如果一个类包含抽象方法,那么该类必须是抽象类。 2.任何子类必须重写父类的抽象方法,或者声明自身为抽象类。 继承抽象方法的子类必须重写该方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该抽象方法,否则,从最初的父类到最终的子类都不能用来实例化对象。
public class Class001_Abstract extends Object{ public static void main(String[] args) { //创建 具体子类的对象调用成员 Java java = new Java(); java.work(); java.work2(); java.sleep(); Demo d = new Demo(); d.work2(); d.work(); d.test(); //多态 Develop develop = new Java(); develop.work(); } } //开发部 abstract class Develop{ //属性 int i =1; static int j = 2; //抽象方法体 : 方法体不知道定义什么,不确定如何定义,那就不定义 abstract void work(); abstract void work2(); //普通方法 public void test(){ System.out.println("抽象类中的普通方法"); } } //具体子类 class Java extends Develop{ @Override void work() { System.out.println("边敲代码边睡觉..."); } @Override void work2() { System.out.println("重写后的方法.."); } //新增 void sleep(){ System.out.println("睁着眼睛睡觉..."); } } //抽象子类 abstract class DB extends Develop{ @Override void work() { System.out.println("重写后的work"); } //abstract void work2(); } class Demo extends DB{ @Override void work2() { System.out.println("我是Demo当中的work2"); } }
2.9接口
1,接口 : 特殊的抽象类
接口是一个引用数据类型
接口为抽象功能的集合
类单继承机制,接口是多实现机制
接口定义开发规范 解耦,降低耦合度
2,定义: interface定义接口 接口->通过implements实现接口
父类->需要通过extends继承父类 继承与实现的区别 : 子类继承父类,就可以直接有权使用父类中的成员(侧重点:直接拿过来就用)
实现类实现接口,实现类就拥有了接口定义的功能,但是功能都是抽象的,没有方法体的,需要实现类自己去实现的(侧重点在于方法的实现,称为实现类)
3,使用:
1.接口不能实例化
2.需要通过实现类实现接口使用 具体的实现类: 重写所有的抽象方法 + 按需新增 抽象的实现类: 按需重写抽象方法 + 按需新增
3.类只能被类继承,接口只能被类实现
4.类只能单继承父类,但是可以实现多个接口
5.先继承父类后实现接口
6.一个接口可以继承多个接口,接口可以多继承接口
7.避免实现的多个接口中存在相同的方法
8.类只能单继承父类,但是可以实现多个接口 9.先继承父类后实现接口
public interface Class01_Interface { public static void main(String[] args) { System.out.println(Malay.num); Impl1 impl1 = new Impl1(); impl1.num(); impl1.test1(); impl1.test(); } } //创建一个接口 interface Malay{ //公共静态的常量 public static final int num = 5; //公共的抽象方法 public abstract void test(); public abstract void test1(); } //具体的实现类 class Impl1 implements Malay{ @Override public void test() { System.out.println("开心学习每一天"); } @Override public void test1() { System.out.println("高高兴兴每一天"); } public void num(){ System.out.println("学习使我快乐"); } } //抽象的实现类 abstract class Impl2 implements Malay{ @Override public void test() { System.out.println("吃饭"); } public void info(){ System.out.println("睡觉"); } } class Son extends Impl2{ @Override public void test1() { } }
2.91JDK8接口新增
1.静态方法 只能通过接口名调用,不同通过实现类对象调用 2.默认方法 被default关键字修饰的方法 只能通过实现类对象调用
public class Class003_Interface_JAVA8 { public static void main(String[] args) { MyInterface2.testStatic(); new Impl3().testDefault(); } } interface MyInterface2{ //静态方法 public static void testStatic(){ System.out.println("接口中的静态方法"); } //默认方法 public default void testDefault(){ System.out.println("接口中的默认方法"); } } //实现类 class Impl3 implements MyInterface2{ }
3.0数组
3.1 特点
定长
长度一旦确定不可以改变。
相同数据类型
其元素必须是 相同 类型,不允许出现混合类型。数组中的元素可以是任何数据类型,包括基本类型和引
用类型。
位置有序元素所在的位置是有序的。
数组本身属于引用类型
数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身
就是对象Java 中对象是在堆中的,因此数组无论保存基本类型还是其他对象类型,数组对象本身是在堆
中的。
数组中可以存储任意类型的数据
3.2 定义**
1.3数组声明格式**
注意 : 引用数据类型只声明不赋值存在默认值null
1.4数组初始化**
动态初始化
数组定义与为数组元素分配空间和赋值的操作分开进行
注意:元素为引用数据类型的数组中的每一个元素都需要实例化。
静态初始化
在定义数组的同时就为数组元素分配空间并赋值
数据类型[] 数组名称; --推荐使用
数据类型 数组名称[];
double[] arr;
char arr2[];
数据类型[] 数组名=new 数据类型[长度];
int[] data = new int[5];
Person[] people; //声明说组
people = new Person[3]; //创建数组
people[0] = new Person(); //数组中元素实例化
people[1] = new Person();
people[2] = new Person();
数据类型[] 数组名=new 数据类型[]{值1,值2...};
数据类型[] 数组名={值1,值2...}; --当面的简写方式数组类型
默认初始值
byte 0
short 0
int 0
long 0
char 编码为0的字符
String(引用类型) null
float 0.0
double 0.0
boolean false
注意:
对于返回值类型为数组类型的方法来说,我们可以 return new int[3]; ,我们也可以 return new
int[]{1, 2, 3}; ,但我们不可以 return {1, 2, 3}; 。即简写方式,其不能脱离数组的声明, {1,
2, 3} 并不能返回一个数组对象。
1.5 数组元素的界限**
定义并用 new 为之分配空间之后,才可以引用数组中的每个元素,数组元素的引用方式为:
index为数组元素下标|索引,可以是整型常量或整型表达式 , 可以根据数组元素的下标操作数组中数
据。如:
数组元素下标从0开始;长度为n的数组的合法下标取值范围为
0~n-1
每个数组都有一个属性length指明它的长度
a.length的值为数组a的长度(元素的个数)
1.6数组的遍历方式
普通for:
for(int 索引=0;索引<长度; 索引++){
数组名称[索引] = 值;
}
增强for:
for(元素类型 局部变量 : 数组){
局部变量-->为数组中的每一个元素值,从左向右以此获取
}
1.7:
一维数组: 数组中放数据 二维数组 : 了解 数组中放数组
声明 : 数据类型[][] 数组名; --> 推荐 数据类型 数组名[][]; 数据类型[] 数组名[]; 初始化 : 创建及第一次赋值 动态初始化 : 先创建数组,后赋值 数据类型[][] 数组名 = new 数据类型[外层二维数组的长度][内层的每一个一维数组的程度]; 数据类型[][] 数组名 = new 数据类型[外层二维数组的长度][]; 数组名[二维索引] = new 数据类型[一维长度]; ... 静态初始化 : 创建数组的同时赋值 数据类型[][] 数组名 = new 数据类型[][]{{1,2,3},{4,5},{6}...}; 数据类型[][] 数组名 = {{1,2,3},{4,5},{6}...};
使用 根据索引操作 二维数组名[二维的索引][一维的索引] 遍历 双重for循环嵌套 外层for循环遍历外层的二维数组,内存for循环用来遍历内层的每一个一维小数组 增强for与普通for相互嵌套 普通-->普通 普通-->增强 增强-->增强 增强-->普通
public class Class002_Array { public static void main(String[] args) { //动态初始化 int[][] arr = new int[2][3]; //赋值 arr[0][0] = 1; arr[0][1] = 2; arr[0][2] = 3; arr[1][0] = 4; arr[1][1] = 5; arr[1][2] = 6; System.out.println(arr[0][0]); System.out.println(arr[0][1]); System.out.println(arr[0][2]); System.out.println(arr[1][0]); System.out.println(arr[1][1]); System.out.println(arr[1][2]); //动态初始化 String[][] arr2 = new String[2][]; arr2[0] = new String[3]; arr2[0][0] = "你"; arr2[0][1] = "好"; arr2[0][2] = "帅"; arr2[1] = new String[]{"中","国"}; System.out.println(arr2[0][0]); System.out.println(arr2[0][1]); System.out.println(arr2[0][2]); System.out.println(arr2[1][0]); System.out.println(arr2[1][1]); //静态初始化 int[][] arr3 = new int[][]{{1,2,3},{4,5},{6}}; //静态初始化 double[][] arr4 ={{1.1,2.2,3.3},{4.4,5.5},{6.5}}; //遍历 //普通-->普通 //i 外层二维的索引 for(int i=0;i<arr3.length;i++){ for(int j=0;j<arr3[i].length;j++){ System.out.println(arr3[i][j]); } } //增强嵌套普通 for(double[] a:arr4){ for(int i=0;i<a.length;i++){ System.out.println(a[i]); } } } }
3.3Arrays
3. 4:Arrays**中常用方法**
打印数组----toString方法。
比较两个数组是否相同----equals方法。
数组排序----sort方法。
数组查找----binarySearch 方法。
数组拷贝----copyOf方法。
数组拷贝----copyOfRange方法。
public class Class003_Arrays { public static void main(String[] args) { int[] arr1 = {3,1,5,4,2}; int[] arr2 = {3,1,5,4,2}; char[][] arr3 = {{'a','b'},{'c','d','e'}}; char[][] arr4 = {{'a','b'},{'c','d','e'}}; //static String toString(int[] a) 返回指定数组内容的字符串表示形式。 System.out.println(Arrays.toString(arr1)); //static boolean equals(int[] a, int[] a2) 如果两个指定的int数组彼此 相等 ,则返回 true 。 System.out.println(arr1==arr2); System.out.println(Arrays.equals(arr1,arr2)); //针对于多维数组 //static boolean deepEquals(Object[] a1, Object[] a2) 如果两个指定的数组彼此 深度相等 ,则返回 true 。 System.out.println(Arrays.equals(arr3,arr4)); System.out.println(Arrays.deepEquals(arr3,arr4)); //static String deepToString(Object[] a) 返回指定数组的“深层内容”的字符串表示形式。 System.out.println(Arrays.toString(arr3)); System.out.println(Arrays.deepToString(arr3)); //static void fill(boolean[] a, boolean val) 将指定的布尔值分配给指定的布尔数组的每个元素。 //static void fill(boolean[] a, int fromIndex, int toIndex, boolean val) 将指定的布尔值分配给指定的布尔数组的指定范围的每个元素。 结束索引位置不包含 boolean[] arr5 = new boolean[10]; System.out.println(Arrays.toString(arr5)); Arrays.fill(arr5,true); System.out.println(Arrays.toString(arr5)); Arrays.fill(arr5,3,6,false); System.out.println(Arrays.toString(arr5)); //static void sort(int[] a) 将指定的数组按升序排序。 //static void sort(int[] a, int fromIndex, int toIndex) 按升序对数组的指定范围进行排序。 System.out.println(Arrays.toString(arr1)); //Arrays.sort(arr1); Arrays.sort(arr1,1,4); System.out.println(Arrays.toString(arr1)); //自行测试对字符数组|字符串数组默认升序排序 //static int binarySearch(int[] a, int key) 使用二进制搜索算法在指定的int数组中搜索指定的值。如果不存在返回-插入点-1 --> 默认数组升序排序为前提 Arrays.sort(arr2); System.out.println(Arrays.toString(arr2)); System.out.println( Arrays.binarySearch(arr2,6));; //-插入点-1 //数组拷贝 //static int[] copyOf(int[] original, int newLength) 使用零复制指定的数组,截断或填充(如有必要),以使副本具有指定的长度。 //original 原数组 newLength 新数组的长度 //当newLength == original.length 原数组长度--> 拷贝 int[] newArr = Arrays.copyOf(arr1,5); System.out.println(Arrays.toString(newArr)); System.out.println(arr1==newArr); //当newLength < original.length 原数组长度--> 截取 : 从原数组中所有为0的位置开始,拷贝newLength个到新数组中 System.out.println(Arrays.toString(Arrays.copyOf(arr1,3))); //当newLength > original.length 原数组长度--> 填充 : 原数组中的数据原封不动拷贝到新数组中,剩余空间默认值填充 System.out.println(Arrays.toString(Arrays.copyOf(arr1,10))); //static int[] copyOfRange(int[] original, int from, int to) 将指定数组的指定范围复制到新数组中。 结束索引一般不包含 System.out.println(Arrays.toString(Arrays.copyOfRange(arr1,1,3))); //copyOf与copyOfRange实现拷贝,新数组都是方法内部创建的,不是用户手动创建 //目的地数组需要用户手动指定,可以使用 //static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) 将指定源数组中的数组从指定位置开始复制到目标数组的指定位置。 int[] arr6 = new int[8]; System.arraycopy(arr1,1,arr6,4,3); System.out.println(Arrays.toString(arr6)); } }
3.1内部类
1,内部类 了解,理解 类中定义类 2,内部类的分类: 成员内部类 静态内部类 私有内部类 局部内部类 匿名内部类 * lambda表达式**** 3,成员内部类 : 内部类定义在外部类的成员位置 当一个类的成员也是另外一种事物,这个成员可以定义为内部类 成员内部类也是类具有类的特点,能够继承父类,能够实现接口,也具有成员的特点,可以被成员修饰符修饰 4,注意: 只有静态内部类中才能定义静态内容,其他内部类中不能定义静态内容除了静态常量 成员内部类中可以直接使用外部类中的成员,包括私有的 外部类中需要通过成员内部类的对象方法成员内部类的成员 其他类中使用成员内部类中的成员需要通过外部类对象构建内部类对象,通过内部类对象调用内部类成员 Class001_Outer.Inner in = new Class001_Outer().new Inner();
3.2成员内部类
public class Class001_Outer { //成员位置: 类中方法外 private int a = 100; private static int b = 200; //成员内部类 public class Inner extends Object{ //成员内部类中的属性 int i = 1; static final int j = 2; //成员内部类中的功能 public void inner(){ System.out.println("成员内部类中的成员方法inner"); System.out.println(i); System.out.println(j); System.out.println(a); System.out.println(b); } } //外部类中的成员方法 public void outer(){ System.out.println("外部类中的成员方法outer"); //创建内部类中的对象访问内部类的成员 Inner in = new Inner(); System.out.println(in.i); System.out.println(in.j); in.inner(); } }
package com.yjxxt.inner01; //同名成员调用问题 public class Class003_Outer { int i=1; static int b=5; class Inner{ int i=2; public void inner(){ int i=3; //调用的是局部变量 inner方法中的变量i=3 System.out.println(i); //调用的是内部类Inner作用的变量i=2 System.out.println(this.i); //this内部类Inner对象 //调用的外部类中的变量i System.out.println(Class003_Outer.this.i); //this内部类的对象所依赖的外部类对象 } } }
3.3静态内部类
1,静态内部类 静态内部类中可以直接定义静态内容 在静态内部类中使用外部类中的成员需要通过外部类对象使用,因为内部类是静态的,使用外部类中的静态内容,可以直接使用 外部类中需要通过静态内部类的对象调用静态内部类的成员,可以通过静态内部类的类名.调用静态内部类的静态内容 其他类中使用静态内部类中的静态内容,通过外部类的类名.静态内部类的类名.调用静态内容 其他类中使用静态内部类中的成员内容,通过new 外部类的类名.静态内部类的类名的对象.调用成员内容
public class Class005_Outer { private int a = 100; private static int b = 200; //静态内部类 static class Inner{ //成员变量 int i = 1; //静态变量 static int j = 2; //成员方法 public void inner1(){ System.out.println("静态内部类中成员方法"); System.out.println(i); System.out.println(j); System.out.println(b); System.out.println(new Class005_Outer().a); } //静态方法 public static void innerStatic2(){ System.out.println("静态内部类中静态方法"); System.out.println(j); Inner in = new Inner(); System.out.println(in.i); System.out.println(new Class005_Outer().a); System.out.println(b); } } //外部类中的成员方法 public void outer(){ System.out.println("外部类中的成员方法"); System.out.println(Inner.j); Inner.innerStatic2(); Inner in = new Inner(); in.inner1(); } }
3.2.3局部内部类
局部内部类:定义在局部位置的内部类成为局部内部类局部内部类不能被private,public,protected,static 等 成员修饰符修饰(可以被final修饰)如果在局部内部类中使用所在方法的局部变量,默认被final修饰(jdk1.8及之后,1.7及之前需要手动final修饰)局部内部类只能在所在方法中通过对象访问成员
public class Class01_Outer { //成员变量 int i = 5; public void test(){ //局部 final int s = 10; //局部类 class Inner{ int n = 20; static final int j = 1; //局部内部类的成员方法 public void inner(){ int s1 = 1; System.out.println("局部内部类的成员方法"); System.out.println(i); } } //创建局部内部类对象 Inner num = new Inner(); System.out.println(num.n); } public void outer(){ } public static void main(String[] args) { } }
3.2.4匿名内部类
1,匿名内部类 作用: 简化没有自己本身作用的实现类|之类(实现了接口,继承了父类-> 重写方法),需要在实现类中重写方法的,并且使用次数较少--> 可以通过匿名内部类简化
public class Class02_Outer { public static void main(String[] args) { //定义接口实现类对象 Test test = new Test(); test.smoking(); //创建匿名内部类对象,只能调用一次 new Smoke(){ @Override public void smoking() { System.out.println("一边干活,一边吸烟"); } }.smoking(); //多次调用,接口多态可以多次调用 Smoke smoke = new Smoke() { @Override public void smoking() { System.out.println("一边吸烟,一边敲代码"); } }; smoke.smoking(); smoke.smoking(); //定义方法参数的传递,先传参然后在创建接口对象实现 testSmoke(new Smoke() { @Override public void smoking() { System.out.println("一边吸烟,一边聊天"); } }); } public static void testSmoke(Smoke smoke){ smoke.smoking(); } } //定义一个接口 interface Smoke{ //方法 void smoking(); } class Test implements Smoke{ @Override public void smoking() { System.out.println("一边喝酒,一边吸烟"); } }
3.2.5Lambda表达式
public class Class01_Lambda { public static void main(String[] args) { //创建匿名内部类对象 /* Swim swim = new Swim(){ @Override public void swimming() { System.out.println("一边游泳一边听歌"); } }; swim.swimming();*/ //Lambda表达式1 /*Swim swim = ()->{ System.out.println("一边游泳一边喝水"); };*/ //lambda表达式写法2 : 如果{}中方法体语句只有一句,前后的{}可以省略 /*Swim swim = ()-> System.out.println("一边游泳一边喝水");*/ //lambda表达式写法3 : 如果存在参数,参数的数据类型可以省略4 //Swim swim = (name)-> System.out.println(name+"一边游泳一边喝水"); //lambda表达式写法4 : 如果存在参数,参数只有一个,参数列表前后()可以省略 //Swim swim = (s)-> System.out.println(s+"一边游泳一边喝水"); //lambda表达式写法5 :如果方法存在返回值,并且方法体语句只有一句,就是return语句,前后的{}与return关键字可以一起省略 Swim swim = age -> age > 20; swim.swimming(30); System.out.println(swim.swimming(30)); //创建对象 test(new Swim() { @Override public boolean swimming(int age) { return age>20; } }); System.out.println(swim.swimming(21)); test((int age)->{ return age>20; }); swim.swimming(21); System.out.println(swim.swimming(21)); test(age -> age>20); } static void test(Swim swim){ swim.swimming(19); } } //定义接口 interface Swim{ boolean swimming(int age); }
3.3异常
3.3.1异常体系
1,Exception 异常 java中程序一旦遇到异常,程序无法继续向下执行
Throwable
/ \
Error Exception
2,Error: 错误,一般是由虚拟机生生成并脱出的,不需要程序猿控制,程序媛不关注
Exception : 异常
检查时异常|编译时异常 : 编译期间遇到的异常,如果不处理,程序语法运行
运行时异常 : 运行期间遇到的异常,通过增强程序健壮性的代码就可以解决 if...
3,常见的运行时异常:
1.空指针异常 NullPointerException
2.数组索引越界 ArrayIndexOutOfBoundsException
3.类型转换异常 ClassCastException
4.数学异常 ArithmeticException
5.格式转换异常 NumberFormatException
public class Class01_Exception { public static void main(String[] args) { //1.空指针异常 NullPointerException System.out.println("main----->开始了"); String str = null; if (str!=null) System.out.println(str.length()); System.out.println("main----->结束了"); //2.数组索引越界 ArrayIndexOutOfBoundsException int[] arr = new int[5]; int i = 6; if (i>=0 && i<arr.length-1){ System.out.println(arr[i]); } //3.类型转换异常 ClassCastException String s = "123456"; System.out.println(Integer.valueOf(s)); System.out.println("------------结束----------"); } }
3.3.2异常处理方案*
1,异常处理方案: * 1.抛出异常 throws 异常类型 2.异常捕获 try...catch try{ 有可能出现异常的代码; }catch(FileNotFoundException e){ 遇到异常后执行的代码; }catch(NullPointerException e){ 遇到异常执行的代码; }..... catch(Exception e){//-->接盘侠 //Exception e = new ClassCastException(); } finally{ 无论try中是否遇到异常,结束之前都会执行finally中的代码 }
}
2,
注意: 无论是编译时异常还是运行时异常都可以通过2中解决方案处理 但是编译时异常只能通过2种解决方案处理 而运行时异常可以通过2种解决方案处理,也可以通过增强程序健壮性if 一个try后面可以接1~n个catch 如果try中的代码一旦遇到异常try中后面的代码不会执行,会直接判断catch,多个catch之间从上到下判断,如果找到对应的catch,执行{}中的代码 如果存在多个catch,大范围类型的捕获放在最后 一般在finally中会定义资源的关闭等代码
public class Class02_Exception { public static void main(String[] args) { System.out.println("main----------"); try { System.out.println("try------>开始了"); //运行时异常 test(); System.out.println(10/0); System.out.println("try------>结束了"); } catch (FileNotFoundException e) { System.out.println("遇到文件未找到异常");// }catch (ArithmeticException e){ System.out.println("分母为0......"); }finally { System.out.println("世上没有不散的宴席"); } System.out.println("------结束了------"); } public static void test() throws FileNotFoundException { //编译时异常 InputStream in = new FileInputStream("D://test.txt"); } }
3.3.3自定义异常
1,自定义异常 自定义的异常类型需要直接或者间接的继承自Exception 自定义的异常类型为运行时异常需要直接或者间接的继承自RuntimeException throw 制造异常
public class Class03_Exception { public static void main(String[] args) { //创建对象 User num = new User(); num.setId(123456); num.setName("戴总"); //num.setAge(20); //AgeException作为运行时异常 /* int age = 20; if (age>=18 && age<100){ num.setAge(age); }else { num.setAge(21); }*/ //AgeException作为编译时异常 try { num.setAge(28); } catch (AgeException e) { try { num.setAge(18); } catch (AgeException ageException) { ageException.printStackTrace(); } } System.out.println(num); } } //自定义异常 //class AgeException extends RuntimeException { //运行时异常 class AgeException extends Exception{//编译时异常 public AgeException(){ } public AgeException(String message){ super(message); } } class User{ private int id; private String name; private int age; public User() { } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } //运行时异常 /*public void setAge(int age) { if (age<18 && age>100){ throw new AgeException(age+"合法"); } this.age=age; }*/ //编译时异常 public void setAge(int age)throws AgeException { if (age<18 || age>100){ throw new AgeException(age+"不合法"); } this.age=age; } @Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }