day_12
一、Object
1、Object是所有类的父类
声明一个类没有指定父类的时候,默认这个类就是继承于Object的
这个类存放与:java.lang包中
2、toString方法()
Object类提供的toString()方法,所有的类都拥有toString方法
作用:将对象以字符串的形式进行处理
3、getClass()方法
作用:返回正在运行的类是哪一个(第一次学习的同学,在这里不要纠结,只做了解,因为后面的 学习中会使用一个内容叫:反射,反射的前提就是要先找到当前执行的类)
Object o = new Object();
System.out.println(o.toString());
//getClass():获取到当前正在执行的是哪个类
//getName():获取到当前的类的名称是什么
String classPath = o.getClass().getName();
System.out.println(classPath);
People people = new People("张三",20);
System.out.println(people.getClass().getName());
System.out.println(people.toString());
4、equals(Object obj)方法
用于判断两个对象是否相等
public class People extends Object{
private String name;
private int age;
@Override
public boolean equals(Object o) {
//两个对象完全相同
if (this == o) return true;
//如果对象为空或者两个执行的对象不属于同一个类
if (o == null || getClass() != o.getClass()) return false;
//两个类存在继承关系,然后大的数据类型转小的数据类型,判断属性是否相同
//如果属性相同就返回为true
People people = (People) o;
return age == people.age &&
name.equals(people.name);
}
}
public class Test_03 {
public static void main(String[] args) {
People p1 = new People("张三",20);
People p2 = new People("李四",20);
System.out.println(p1.equals(p2));
People p3 = new People("abc",33);
Emp emp = new Emp("abc",20);
System.out.println(p3.getClass().getName());
System.out.println(emp.getClass().getName());
System.out.println(p3.equals(emp));
}
}
5、instanceof:比较两个对象是否相同
当两个类之间存在继承关系,或者类与接口之间存在实现关系,我们可以使用instanceof来判断一个对象是否属于某一个类型。
public void menuDept(){
System.out.println("***************");
System.out.println("1、部门添加信息");
System.out.println("2、修改部门信息");
System.out.println("3、删除部门信息");
System.out.println("4、查询单个部门信息");
System.out.println("5、查询所有部门信息");
System.out.println("***************");
System.out.println("输入你的操作:");
int num = sc.nextInt();
switch (num){
case 1:
Dept dept = new Dept("10001","销售部","45678955");
Emp emp = new Emp("1111","张三","男",30,"后勤部",3000);
//方法的参数默认需要一个Object类型的元素,Object是所有类的父类
//所以在这里的话,虽然Dept没有去写继承Object,但是已经默认继承
boolean flag = deptDao2.add(emp);
if(flag){
System.out.println("添加成功");
}else{
System.out.println("添加失败");
}
menuDept();
break;
}
}
public boolean add(Object o) {
//举个栗子:
// int a = 100;
// double b = a;
// int c = b;
//判断o是不是Dept类型的元素
if(o instanceof Dept){
//如果是就强制转换
//强制转换之后就可以将o的信息转换为Dept类的信息,转换完成之后可以存储到集合中
depts.add((Dept)o);
System.out.println(depts.toString());
return true;
}
return false;
}
6、finalize()
当一个对象没有任何引用执行它的时候,它就会满足垃圾回收机制的要求,被垃圾回收机制回收,会自动调用finalize()方法。不是开发人员自己主动调用的,是由虚拟机自己调用的
public class Test_04 {
//重写这个方法
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("-----正在回收对象-----");
}
public static void main(String[] args) {
Test_04 test_04;//创建一个对象但是没有对这个对象进行实例化 这是一个引用
for(int i = 1; i <= 1000000000; i++) {
//不断创建新的对象
//每创建一个对象,前一个对象,就没有引用执行它
//之前创建的对象一直都没有使用,直接被后面的对象给覆盖了
//没有引用指向这个对象的时候,就已经满足了垃圾回收机制的条件
//当java虚拟机中的内存已经快要存满的时候,后面的对象还在不断的创建,
//为了让后面的元素继续执行,java虚拟就会回收掉之前创建的对象
//一旦某一个对象被回收了,那么就会自动的调用finalize这个方法
test_04 = new Test_04();//地址赋值
}
}
}
7、clone()方法
只要是实现了Cloneable()这个接口的类就可以调用这个方法,这个方法会产生一个新的对象
这个接口的实现是调用方法的前提,否则会抛出异常
protected Object clone() throws CloneNotSupportedException
public class CloneNotSupportedException
extends 异常抛出,表明该clone类方法Object被称为克隆对象,但该对象的类无法实现Cloneable接口。
覆盖clone方法的应用程序也可以抛出此异常以指示对象无法或不应被克隆。
//只要实现这个接口就可以调用clone这个方法
public class Sheep extends Object implements Cloneable{
private String name;
public Sheep(String name) {
this.name = name;
}
public static void main(String args[]) throws CloneNotSupportedException {
//创建对象
Sheep s1 = new Sheep("喜羊羊");
//当你调用一个方法的时候,如果这个方法本身已经抛出了异常,那么你调用它的时候也要抛出异常
Object obj = s1.clone();//新的羊的对象
//如果你想要知道两个对象的地址是否相同就不要toString输入内容,输出的就是地址
System.out.println(s1);//com.softeem.dto.Sheep@4554617c
System.out.println(obj);//com.softeem.dto.Sheep@74a14482
//==:比较两个类的地址是否相同
//equals:首先比较两个字符串的内容是否相同
//如果不是字符串,是两个对象,那么重写equals底层会先判断两个对象是不是相同的
//然后再判断两个对象的类型是否相同,最后再判断对象的属性内容是否相同
//在判断的过程中,我们发现equals底层判断两个对象是否相同的时候使用的是==
System.out.println(obj == s1);//false
System.out.println("s1 = " + s1.name);
Sheep s4 = (Sheep) obj;
System.out.println("obj = " + s4.name);
Sheep s2 = new Sheep("沸羊羊");
Sheep s3 = s2;
System.out.println(s2);//com.softeem.dto.Sheep@1540e19d
System.out.println(s3);//com.softeem.dto.Sheep@1540e19d
}
}
day_13
一、基本数据类型的封装类型
1、在java中8种基本数据类型都有一个与之相对应的封装类,因为基本数据类型不能调用方法和属性。其实基本数据类型你可以将其理解为一个名称,其具体的功能和特点都是封装在封装类型中的。
我们可以通过封装类型去访问数据类型的属性和方法
2、 基本数据类型 封装类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
二、String <------->基本数据类型
1、String 转基本数据类型
static修饰的方法,可以并且建议使用类名进行直接调用
public static int parseInt(String s) throws NumberFormatException
除了char类型,.其余的数据类型都满足
基本数据类型 自定义变量名 = 封装类型.parseXXXX("值");
比如:
static byte parseByte(String s)
将字符串参数解析为带符号的十进制 byte
static long parseLong(String s)
将字符串参数解析为带符号的十进制 long 。
static double parseDouble(String s)
返回一个新 double初始化为指定的代表的值 String ,如通过执行 valueOf类的方法 Double 。
static boolean parseBoolean(String s)
将字符串参数解析为布尔值。
2、基本数据类型转String类型的方法
1、直接使用""进行连接 34 + "" ----> 变为一个字符串
2、调用String类中的重载方法valueOf()
//其余的方法请参考String类的api中,关于valueOf的使用
static String valueOf(int i)
返回 int参数的字符串 int形式。
static String valueOf(char[] data)
返回 char数组参数的字符串 char形式。
3、调用对应的基本数据类型中的toString方法,一般格式是:
static String toString(XXX 变量名)
static String toString(int i)
返回一个 String指定整数的 String对象。
三、Integer类
1、静态常量
static int BYTES
用于表示二进制补码二进制形式的 int值的字节数。
static int MAX_VALUE
一个持有最大值一个 int可以有2 31 -1。
static int MIN_VALUE
的常量保持的最小值的 int可以具有,-2 31。
static int SIZE
用于表示二进制补码二进制形式的 int值的位数。
static 类<Integer> TYPE
类原始类型 int的 类实例。
public static void main(String[] args) {
//使用静态常量进行获取
int max = Integer.MAX_VALUE;
int min = Integer.MIN_VALUE;
int size = Integer.SIZE;//32位
int bytes = Integer.BYTES;//4个字节
//获取基本数据类型是哪一个
System.out.println(Integer.TYPE);
}
2、构造方法
构造方法
Integer(int value)
构造一个新分配的 Integer对象,该对象表示指定的 int值。
Integer(String s)
构造一个新分配 Integer对象,表示 int由指示值 String参数。
只能写能够转换为int类型的字符串,如果不是int类型NumberFormatException
3、静态方法
//将i转换为2进制,然后统计二进制数中1的个数
int count = Integer.bitCount(11);
System.out.println("11的二进制数中1的个数:" + count);//11的二进制数中1的个数:3
//十进制转二进制
String s1 = Integer.toBinaryString(11);
System.out.println("11的二进制数为:" + s1);//11的二进制数为:1011
//使用for循环将10进制转换成2进制
//十进制转十六进制
System.out.println(Integer.toHexString(20));//14
//十进制转八进制
System.out.println(Integer.toOctalString(20));//24
//将前面字符串的元素以后面第二个参数radix的进制进行转换
Integer x = Integer.valueOf("24",8);
System.out.println(x);
//将两个数进行比较之后将最大值拿出来
int m = Integer.max(20,50);
System.out.println(m);
4、非静态方法
/**
* 非静态方法
*/
public class Demo_05 {
public static void main(String[] args) {
Integer m1 = new Integer(20);
Integer m2 = new Integer(20);
int m3 = m1.compareTo(m2);
System.out.println("m3 = " + m3);
//思考一个问题?
//Integer是否继承于Object?
//Integer是否重写了Object中的toString方法
Integer n1 = new Integer(30);
System.out.println(n1.toString());
Integer n2 = new Integer(40);
System.out.println(n1 == n2);
//覆盖了Object中的equals方法,比较的是两个对象的值
boolean flag = n1.equals(n2);
System.out.println(flag);
Object o = new Object();
o.toString();
}
5、int <--------> Integer类型之间的转换
1、int类型转Integer类型
//int转换成Integer方法
//1、通过构造方法
int a = 10;
Integer x = new Integer(a);
Integer y = new Integer(a + "");
//2、通过Integer类中的静态方法
// 参数是int类型返回值是Integer类型
// 使用valueOf()
Integer z = Integer.valueOf(a);
//底层自动装箱操作的时候会自动调用这个方法
2、Integer类型转int类型
//int转换成Integer方法
//1、通过构造方法
int a = 10;
Integer x = new Integer(a);
Integer y = new Integer(a + "");
//2、通过Integer类中的静态方法
// 参数是int类型返回值是Integer类型
// 使用valueOf()
Integer z = Integer.valueOf(a);
//底层自动装箱操作的时候会自动调用这个方法
6、自动装箱和自动拆箱
自动装箱 int -----> valueOf(int n) -----> Integer
自动拆箱 Integer ----> intValue() -----> int
①自动装箱
Integer x = 10; 在java的源文件中
Integer localInteger = Integer.valueOf(10); //自动将int转换成为Integer,自动装箱
②自动拆箱
Integer x = 4;//默认的4是int类型的值而不是Integer
x = x + 5;
Integer localInteger = Integer.valueOf(4);//将int类型转换成Integer类型
//在进行运算的时候,我们需要拿int类型进行运算
//所以先将Integer类型转换为int类型使用了intValue()方法
//然后和5进行运算,运算完成之后的结果因为我们还是将值赋值给了x
//x是Integer,还是需要将最终的结果转换成为Integer
localInteger = Integer.valueOf(localInteger.intValue() + 5);
当你定义的整型数据在-128 ~ 127之间的时候,这个数据没有进入到内存中,在缓存中进行处理,在缓存中,两个变量指向了相同的地址,并没有新建对象,没有产生新的地址.
当不在这个范围内的时候,底层重新新建了变量.新建之后就在内存中开辟了新的空间,产生了新的地址.
==比较两个元素的内存地址是否相同,如果比较的是基本数据类型的元素,那么比较的就是值
day_14
一、String类型创建对象的过程
public static void main(String[] args) {
String s1 = "abc";//将对象信息放在常量池里面
String s2 = "abc";//当第二个字符串创建的时候首先到常量池中去找,如果没有的话就创建,有的话直接引用地址
String s3 = new String("abc");//在堆中直接新建一个地址存储"abc"信息
String s4 = new String("abc");
String s5 = s3.intern();//先去常量池里面进行寻找,有的话就返回,没有的话就创建
//使用+进行连接的时候怎么处理?
//m1和m2是同一个地址
//m2是纯字符串常量进行累加,只会在String常量池中进行寻找
String m1 = "ab";
String m2 = "a" + "b";
System.out.println(m2 == m1);//true
//如果像x2中这样,表达式中包含了一个变量,不仅会去常量池中进行寻找
//而且还会在堆中新建一个新的字符串,因为字符串x1虽然放在了x2中但是,
//字符串String是不可以改变的,一旦改变就会产生新的地址
String x1 = "a";
String x2 = x1 + "b";
System.out.println(x2 == m2);//false
//String类型的p就是一个常量了,是常量就会放在常量池中,纯字符串常量累加,只会在常量池中进行搜索
final String p = "a";
String q = p + "b";
System.out.println(q == m2);//true
String k = "ab";
//链式调用,链式编程
//只会去常量池中进行检查搜索
String s = new String("ab").intern();
System.out.println(k == s);//true
二、字符串(String,StringBuffer,StringBuilder)
只细讲StringBuffer,后面用的相对比较多
String:字符串常量
String类型不可以改变的,每次改变的时候都会产生新的对象,然后将调用信息的索引指向最新的元素。性能相对来说比较差,经常要改变内容的话,不建议使用String
StringBuffer:字符串变量(线程安全,适用于多线程的情况下)
字符串变量,对它进行操作的时候,不会产生新的变量,直接对原来的元素进行修改,性能比较好
StringBuilder:字符串变量(线程不安全,适用于单线程情况下)
不能保证线程的安全性,所以在操作的时候速度最快,性能最好,但是安全性比较低.如果是单线程可以使用StringBuilder
性能上排序:
StringBuilder > StringBuffer > String
总的来说:
String:适用于少量的字符串操作
StringBuffer:适用于多线程下在字符串缓冲区里面进行大量的字符串操作
StringBuilder:适用于单线程下,在字符串缓冲区里面进行字符串的操作
三、StringBuffer类
在学习String类的时候String类是不可以改变的,StringBuffer类的API中说字符串缓冲区支持可变的字符串,什么是字符串缓冲区?
字符串缓冲区:就像一个String类型的变量,但是长度可以改变,不会产生新的地址,API中也提供了一些方法来对这些信息进行更改
你可以将其理解为之前的ArrayList与数组的关系,数组的长度是已经确定的,但是ArrayList可以根据添加元素的个数来进行自动的扩容操作
1、构造函数
StringBuffer()
构造一个没有字符的字符串缓冲区,初始容量为16个字符。
StringBuffer(CharSequence seq)
构造一个包含与指定的相同字符的字符串缓冲区 CharSequence 。
StringBuffer(int capacity)
构造一个没有字符的字符串缓冲区和指定的初始容量。
StringBuffer(String str)
构造一个初始化为指定字符串内容的字符串缓冲区
四、多态
1、多态的概念
多态:多种状态
在面向对象的语言中,接口的不同的实现方式就是多态
多态性:
允许你将你的父类引用设置成为一个或者更多的子类对象
2、多态的格式
1>普通类中
父类 自定义变量名 = new 子类();
比如:
class F{}
class Z extends F{}
F f = new Z();
2、抽象类中
抽象类 自定义变量名 = new 抽象类的子类();
比如:
public abstract class Hero {
public abstract void normalAttack();//普通攻击
}
public class YaSuo extends Hero{
//一个类继承于一个抽象类,就必须实现抽象类中的抽象方法
@Override
public void normalAttack() {
System.out.println("闪现");
}
public void m(){
System.out.println("功击");
}
}
public abstract class Hero {
public abstract void normalAttack();//普通攻击
}
public class HeroTest {
public static void main(String[] args) {
//抽象类不可以创建对象
//我们只能通过子类进行创建对象并且完成方法的重写和调用
Hero hero = new YaSuo();
hero.normalAttack();
}
}
3、接口的多态的格式
接口名 自定义变量名 = new 实现类名称();
比如:
public interface Skill {
public void useSkill();//使用技能的抽象方法
}
public class ChengJie implements Skill{
@Override
public void useSkill() {
System.out.println("使用惩戒的技能");
}
}
public class SkillTest {
public static void main(String[] args) {
//接口不能创建对象,我们就创建实现类的对象
Skill skill = new ChengJie();
}
}
4、引用数据类型的转换
多态的前提:
类和类之间存在继承关系(直接或者间接继承都可以)
类和接口之间存在实现关系
类型转的时候:
向上转型(自动类型转换,小的转大的)
向下转型(强制类型转换,大的转小的,存在风险!!!比如数据丢失)
向上转型
当有子类对象赋值给一个父类的引用的时候,就是向上转型
父类类型 自定义变量名 = new 子类类型();
向下转型
重要的要求:只有一个已经向上转型的子类对象才能向下转型(为了防止转型的时候出现异常:ClassCastException,为了防止这种事情的出现,我们一般要使用instanceof关键字,先来判断这个对象是否是可以转型子类对象)
F f1 = new S();
if(f1 instanceof S){
S s = (s)f1;
}
day_15
一、多态
1、多态的好处和弊端
父类的引用指向子类对象时F f = new S();就会发生向上转型,即把子类类型的对象转换成父类类型,向上转型的好处是隐藏了子类类型,提高了代码的可扩展性。
但向上转型也有弊端,只能使用父类共性的内容,无法使用子类特有的功能,功能有所限制。
//描述动物类,抽取共性的方法
abstract class Animal{
abstract void eat();
}
//描述狗类,继承动物类,重写eat方法,增加一个看门lookHome的方法
class Dog extends Animal{
void eat(){
System.out.println("吃骨头");
}
void lookHome(){
System.out.println("看家");
}
}
//描述猫的类
class Cat extends Animal{
void eat(){
System.out.println("吃鱼");
}
void catchMouse(){
System.out.println("抓老鼠");
}
}
public class Test{
public static void main(String[] args) {
Animal a = new Dog();//多态的形式,创建狗类的对象
a.eat();//调用对象中的方法的时候只能调用重写的
//a.lookHome();子类特有的方法,需要进行向下转型,不能直接使用
//为了使用狗类中的看门的方法,需要进行下次转型
//向下转型的时候可能会出现:ClassCastException异常
//需要在转换之前,判断所属的类型
if(a instanceof Dog){
//相同就会返回为true.就可以直接进行转换
//不相同就不可以使用
}
//向下转型
Dog d = (Dog)a;
d.lookHome();
}
}
什么时候向上转型?
当不需要面对子类类型的时候,通过提供扩展性,或者使用父类的功能就能完成响应的操作的时候,就可以使用向上转型。
什么时候向下转型?
当需要使用过子类特有的功能的时候,就需要向下转型
好处:可以使用子类特有的功能
弊端:需要面对子类对象的时候,可能会出现异常
多态的优势:
1、降低了类之间的耦合度
2、面向抽象编程
3、提高了扩展性
封装:把独享的属性与方法的描述细节隐藏起来,仅仅对外提供调用这个功能的访问的方式
继承:子类会自动拥有父类的所有可以继承的属性和方法。非私有的
多态:配合继承于方法重写提高代码的可复用性和可扩展性,如果没有方法重写,多态就没有意义
多态里面的成员变量:
当父子类中出现了同名的变量的时候,多态调用变量的时候:
简单记:编译和运行都参考的是等号的左边
多态里面的成员方法:
编译时期:参考引用变量所属的类,如果没有类能够调用的方法,那么就编译失败
运行时期:参考引用变量所指向的对象所属的类,并运行对象所属的类中的成员方法
简单记:编译的看左边,运行的时候看右边
编译的时候要到接口或者抽象类或者父类中去看,有没有你要调用的这个方法,如果有我们就直接执行子类中重写的这个方法,然后将内容进行处理。
编译失败的情况就是,你调用一个方法,这个方法是属于子类或者实现类自己的,那么现在在等号的左边就找不到这个方法,找不到就会出现编译失败.
二、匿名对象
1、匿名对象的概念
匿名对象是指创建的时候只有创建对象的语句,没有把对象的地址给到某一个变量
public class Test {
public static void main(String[] args) {
People people = new People();
people.setName("张三疯");
people.setAge(100);
People people1 = new People("张无忌",20);
System.out.println(people.toString());
System.out.println(people1.toString());
people.eat();
people1.eat();
//创建一个匿名对象
//只能使用一次,使用完成之后就没有了
new People("宋青书",22).eat();
System.out.println(new People("韦一笑",50).toString());
System.out.println(new People("谢逊",60).getName());
ArrayList<People> list = new ArrayList<People>();
list.add(people);
list.add(people1);
list.add(new People("周芷若",20));
}
}
2、匿名对象的特点
1、创建匿名对象直接使用没有对象名
new People().eat();//eat方法被一个没有名字的对象调用了
2、匿名对象在没有指定其引用变量的时候只能使用使用一次
如果想要再次使用这个方法,必须重新创建一个匿名对象
3、匿名对象可以作为方法接收的参数,方法的返回值使用
public class Test {
public static void main(String[] args) {
People people = new People();
people.setName("张三疯");
people.setAge(100);
People people1 = new People("张无忌",20);
System.out.println(people.toString());
System.out.println(people1.toString());
people.eat();
people1.eat();
//创建一个匿名对象
new People("宋青书",22).eat();
System.out.println(new People("韦一笑",50).toString());
System.out.println(new People("谢逊",60).getName());
ArrayList<People> list = new ArrayList<People>();
list.add(people);
list.add(people1);
list.add(new People("周芷若",20));
}
}
4、当对象使用完毕之后就消失,无法再次调用,内存中也没有了
三、内部类
1、内部类概念
什么是内部类?
将类写在其他类的内部,可以写在其他类的成员的位置,也可以写在局部的位置,这时写在其他类内部的类称为内部类。其他类叫外部类。
什么时候使用内部类?
在描述事物的时候,如果一个事务内部还包含了其他可能包含的事物,比如:在描述汽车的时候,汽车内部还包含了发动机,这时发动机类就可以作为汽车类的内部类。
内部类的分类:
成员内部类 局部内部类
我们定义内部类的时候,就是一个正常的定义类的过程,同样包含了修饰符,继承以及实现关系。在内部类中可以直接访问外部类中的所有成员。
2、成员内部类(静态内部类 和 非静态内部类)
成员内部类:定义在外部类中成员的位置,与类中成员变量是相似的,可以通过外部类对象进行访问
<1>定义的格式
public class 外部类{
public class 内部类{//非静态内部类
//其他代码
}
}
<2>创建成员内部类对象
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
<3>成员内部类代码
public class Body {//外部类
private boolean life = true;//生命状态
public class Heart{//内部类 心脏 (非静态内部类)
public void jump(){
System.out.println("心扑通扑通的跳");
System.out.println("生命状态" + life);//内部类可以直接访问外部类中的成员
}
}
public void eat(){
System.out.println("身体需要吃来保证生命状态");
}
public static void main(String[] args) {
//访问内部类
Body.Heart bh = new Body().new Heart();
//调用内部类中的方法
bh.jump();
}
}