java 学习笔记(七)

131 阅读14分钟

多态性:对象的多种形态

Person p = new Man(); 即父类的引用指向子类的对象(想象继承性时子类利用父类那么多态性就是反过来父类利用子类)并且p调用的方法时子类重写父类的方法 ,不能调用子类其他的方法 想想继承性除了继承父类还进行了改编所以父类就用多态的形式来调用

Person p = new Man(); 编译看左边即p.eat()点的时候发现时person中的eat() 运行看右边:即得出的结果时子类中的方法 想想继承性除了继承父类还进行了改编所以父类就用多态的形式来调用

前提:类的继承和方法的重写

package com.atguigu.java1;

public class AnimalTest { public static void main(String[] args) { // Animal animal=new Cat();这里写也麻烦

	AnimalTest test=new AnimalTest();//★因为再main里面所以一定要声明
	test.func(new Cat());//这里就很关键 减少了new Cat和Dog步骤。。。。。
	//这里的new Cat()==下面的Animal animal
}
public void func(Animal animal)//记住这个格式 想象本来要父类的方法但是形参确实个子类所以调用子类方法
{
	animal.eat();
	animal.shout();
	
}

} class Animal { public void eat() { System.out.println("动物:进食"); } public void shout() { System.out.println("动物:叫"); } } class Dog extends Animal { public void eat() { System.out.println("狗吃骨头");

}
@Override
public void shout() {
	System.out.println("汪汪汪");
}

} class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } public void shout() { System.out.println("喵喵喵"); } }

当看到有多个子类继承父类 时说不定可以用多态性

Animal animal  = new Cat();
	animal.eat();//单独用多态性

多态性针对属性时是编译运行都看左边,想象方法比属性高级所以方法可以采用这种多态性的特殊形式

ArrayList的remove可以index或者str

虚拟方法的调用 Person p = new Student(); 编译时认为时调用父类的方法(所以被称为虚拟方法)但调用时却时子类的方法 动态绑定:编译时认为时父类 运行时认为时子类

public Student  duotai()
{
	return new Teacher();
}

将Student想象int int i = 3 则这里的3为new Teacher();

面试题:多态时运行时行为 上次还有一个时方法的重载与重写的区别 (还是以后再记吧)

对于重载 在方法调用之前,即在编译期调用地址就绑定了(确定了调用哪个方法)被称为 早绑定或者静态绑定(想象数组的静态赋值,很早就确定了值)重写就是多态(想象Person p = new Student())

Person p = new Student() 实际上加载了子类特有的属性和方法,但是由于变量为父类类型,所以编译时只能调用父类的属性方法,所以只有进行强制类型转换将父类转换为子类 Student s=(Student) p

基本数据类型的自动类型提升 直接写就好 但是强制类型转换加()与其相同

所以Person s = new Student();就是向上转型即多态

	Student student2 = new Teacher();
	System.out.println(student2.age);
	Teacher teacher2=(Teacher)student2;
	System.out.println(teacher2.age);
	teacher.work();

进行强转后才能调用特有的方法 classcastexception 类型转换异常

Person s = new Student() 想 s。什么就是再Student中找Person 如何再其中找Student呢就必须转换

instanceof为关键字

a instanceof A 判断对象a是否时类A的实例(instance)

​ System.out.println(teacher2 instanceof Teacher);

A2可以时A1的父类(想象子类里面有父类的一部分所以可以)

子类中 public void eat()

{

​ super.eat();//这是调用父类中的eat

}

实例变量(想实例时对象f)=成员变量

Student[] students = new Student[2]; students[0]=new Teacher(); students[1]=new Customer();

for(int i =0;i<students.length;i++)

{

​ students[i].eat();

​ students[i].sleep();//调用方法感觉这种方式比直接定义fuc函数再调用好(想象要调用多种子类的相同方法只需要先数组后for)

}

这个是父类的数组

非共有的类 只有再同一个包中能作为父类?????

final表示继承数的末端,不能被继承

给方法final 这个方法不能被覆盖,给类final的话表示类中所有方法都不能被覆盖

重载只看方法名及其后面

存取权限:private public

Person person = new Man();
	Woman woman=(Woman)person;

这样就是classcastexception 编译通过但是运行不行

Object obj = new Woman();

Person P = (Person)obj 可以的因为上面Woman中有Person的结构所以可以p.来调用person

Person p = new Person()

Man m = (Man) Person 不行 因为上面Person无下面Man结构 不能通过m.来调用man

1.Person p = new man();自动类型提升 因为这里man里面有Person的结构所以可以,并可以调用p

2.Man m=(man)p 可以

原因:1.向上转型一定程度上允许子类扩展超类的部分隐藏,通过父类引用变量只能调用父类中的方法来实现2.中如果有强制类型中的结构才可以被转换

算了开发中一般用多态,向下转型就算了浪费时间

再main中输出子类中的属性是先再子类中找没找到再去父类

==对于引用数据类型 比较的是地址值

★多态性不看属性所以还是父类的属性

返回类型为String return "Name: "+ name + "\nage: "+ age "\nschool: "+ school+"\nmajor:"+major;//这个返回★ 就是syso里面的东西

多态是运行时行为 因为右边子类可以有多种形态可以调用只有运行后才知道用的是谁

int[] a = int... a

默认根父类为Object Object类无属性有空参构造器

方法finalize 想最终化 即垃圾回收 但是不要主动调用 一般都是再垃圾回收前垃圾收集器调用

p.getClass().getSuperClass() 返回对像类 的 超类

面试题 == 与 equals区别

==:1.基本数据类型 有自动类型提升 所以 int 可以和double char(可以是字符也可以数字)除了boolean都可以比较(不一定类型要一样)2.引用数据变量比较的是地址值★包括String

	String str1 = new String("dsad");
	String str2 = new String("dsad");
	System.out.println(str1==str2);//false

equals()是方法不能使用再基本数据类型中 Object类中equals方法的定义:和==一样比较地址值

public boolean equals(Object anObject) { if (this == anObject) { return true;

String Data 包装类 file等等都是重写了Object类中的equals 比较的是对象中的属性是否相同

背的方法 先想==比较地址值 String中equals比较内容 那么Object的equals自然就是==注意String的==也是比较地址 equals才是内容 看到==想象数组a==数组b比较的是地址所以false

char[] a = char a[]

在子类中快捷键生成equals 在main中调用这个equals就是为了比较属性存在的

package com.atguigu.java1;

public class OrderTest { public static void main(String[] args) { Order order1 = new Order(12, "Tom"); Order order2 = new Order(12, "Tom"); System.out.println(order1.equals(order2)); } } class Order { int orderId; String orderName; public int getOrderId() { return orderId; } public void setOrderId(int orderId) { this.orderId = orderId; } public String getOrderName() { return orderName; } public void setOrderName(String orderName) { this.orderName = orderName; } public Order(int orderId, String orderName) { super(); this.orderId = orderId; this.orderName = orderName; } public boolean equals(Object obj) { if(this==obj) { return true; } if(obj instanceof Order) { Order order=(Order)obj;//原因是上面用了多态下面必须向下转型才能用子类的属性 return order.orderId==this.orderId && order.orderName.equals(this.orderName);//这里后者为==就会false因为比较地址值了 } else { return false;//如果传入不是Order就false因为本身就要求两个Order比较 }

}

}

判断String是否相等一定要equals因为这个是直接判断内容

而且String str1 = "AA"与String str2 = "AA"它们==是相同的因为没有new所以★都在常量池中创建AA,但是想由于它的容积小所以如果有相同的字符串被创建就会指向同一个地址 与之相对只有new时才会在堆中创建两个不同的地址放AA

String str1 = "AA";
	String str2 = "AA";
	System.out.println(str1==str2);//true
	String str3 =new String("AA");
	String str4 = new String("AA");
	System.out.println(str3==str4);//false

★说这么多总结就是 看到str相比就必须equals才能达到比较内容的目的,看到其他类比如Customer就自己快捷键equals在main里面调用,==永远比较的是地址

Object中的eqauls没有String中的详细所以只能判断地址值(想象Object时最原始的所以什么具体的功能都不会)

	Order order = new Order();
	System.out.println(order);
	System.out.println(order.toString());//两者都是com.atguigu.java1.Order@dcf3e99

to String return的时return getClass().getName() + "@" + Integer.toHexString(hashCode());

syso里面也用了toString

与equals相同String,Data,File,包装类中的的syso也进行了重写

​ String str1 = "AA"; ​ System.out.println(str1);//为AA

str1.toString结果也是AA

当然其他类的时候就直接用快捷方法

重写toString后syso(对象)出现的就是对象的属性

原因:每一个基本数据类型都对应一个包装类为的就是让基本数据类型具有类的特征根类也为Object

除了 Integer和1 Character 虚框中父类为Number

终于明白了syso(str)为什么输出str了因为本来String 重写了toString() 与之同理 :

	Integer integer = new Integer(10);
	System.out.println(integer);

new Integer()里面可以写"123"但是不能"123a"即不能有字母猜想是因为里面有radix(进制)所以涉及除法之类的

3.15

Integer的printIn也是重写了的

将基本。。。转换为引用。。是因为public void func(Object object)这个时候才可以把它们放进去

但是类不能加减所以又想到了 转换回基本。。。 int i =integer.intvalue

	Integer integer = new Integer("123");
	int i  = integer.intValue();
	System.out.println(i);//输回int 的i

.intValue()想调的是 中的int型的值的方法

Integer integer = 10;//自动装箱 自动将int变为Integer
	System.out.println(integer);

想象从int的10变到了 Integer作为了变量integer

int i = integer;
System.out.println(i);//自动拆箱
Double double1 = 10.0;
System.out.println(String.valueOf(double1));
float f = 12.2f;
System.out.println(String.valueOf(f));

没有字符类关系不能强转

	String string= "123";
	int i =Integer.valueOf(string);
	System.out.println(i);
	System.out.println(Integer.valueOf(string));
	int j = integer.parseInt(string);
	System.out.println(j);

结果都为123

Integer.parseInt()和Integer.valueOf()这些括号中的str必须都是数字不然报错

但是Boolean.parseBoolean()如果str为"true1"则会返回false

包装类和基本数据类型就直接转换 但是把它们看作一个整体与String转换时都互相使用valueOf

String.valueOf() Integer.valueOf()

	Integer integer = 10;
	fuc(integer);//输出10 想象obj.方法==integer.方法所以obj==integer当然直接fuc(10)也行 因为 Integer integer= 10
	
}
public static void fuc(Object obj)
{
	System.out.println(obj);
}

Object o1 = true ? new Integer(1) : new Double(2.0) 因为(要求两边数据类型相同)自动类型提升所以输出1.0

syso(char[])输出数组

包装类把基本数据类型作为一个属性在里面并加入了一些方法

IntegerCache表示Integer的缓存区里面放的时经常使用的-128-127的数字如果Integer i = ? Interger j = ? ?再次范围内就不用去new一个?了所以 i==j 地址值相同

while()里面为true往下面进行并不是while(num)并不代表while(num>0)

3.16

	int num = scanner.nextInt();
	
	while(num>0)//不要这么写

应该为 while(true)

{

​ int score = scanner.nextInt();

​ if (score>0)

​ ......

}

max = (Integer)vector.elementAt(length-1); min = (Integer)vector.elementAt(length-2);//通过这样的方法进行比较太过于复杂,应该先假设max=0,如果又大于0的再把max付给他这样很方便(想象max从0到最大)

public void fuc(Object object)这时候丢入一个int 也是自动装箱

while和for中的continue break一样

package com.atguigu.java1;

import java.util.Scanner; import java.util.Vector;

import org.junit.experimental.max.MaxCore;

public class StudentTest { public static void main(String[] args) { Vector vector = new Vector(); Scanner scanner = new Scanner(System.in); int max=0; while(true)//★ { System.out.print("请输入成绩:"); int num = scanner.nextInt(); if(num<0) { break; }else if(num>100) { System.out.print("请重新输入成绩:"); continue; } vector.addElement(num);

		if(max<num)
		{
			max=num;
		}

​ ​ } ​ for (int i =0;i<vector.size();i++) ​ { ​ Integer integer =(Integer)vector.elementAt(i);//体会下吧 ​ if(max-integer<=10)//定义max时必须在while外面不然就无法再次使用。。。(不知道为什么) ​ { ​ System.out.println("A");//后面就不屑了 ​ } ​ }

}

}

instanceof(小写o)右边必须为对象的类或者父类

多态性:就是为了public boolean equals(Object object)可以调用很多不同类

JDBC想java database caozuo 所以 时java程序操作数据库进行CURD(增删改查)

数组也是继承于Object(想toString)

两个对象是否相同必须类也相同不同类属性相同也是不同的

NumberFormatException 就是包装类与String没转换好

static规定的变量就不归具体的变量

所有例如中国人的国籍都是中国,这个是固定的

不能修饰构造器

	Chinese chinese = new Chinese();
	Chinese chinese2= new Chinese();
	chinese.nation = "China";
	System.out.println(chinese2.nation);//想共用了一个属性

static不能修饰局部变量只能时类中的属性(想想比较高级)成为静态属性(变量)非静态属性(实例变量)(想对象就是实例所以归对象所有)静态属性又称类变量(归类所有)随着类的加载而加载早于对象的加载即可以★不声明对象直接使用

	Chinese.nation = "China";//写Chinese瞬间类就加载号了
	System.out.println(Chinese.nation);//China

由于类只加载一次所以静态变量也是只存在一份 在方法区的静态域(域:field(属性))

无法用类调用实例变量 因为其归具体对象所有

静态属性:Math.PI 因为没有 new Math()

Chinese.nation 写Chinese瞬间就在方法去加载了类

★对象修改静态属性的时候 因为只存在一个所以。。。。。。

静态方法与静态属性一样 Chinese.say();直接调用不创建对象在同一个类中直接say();

静态方法中只能调用静态的方法和属性想象类加载的只有静态的东西,而非静态方法都可以调用因为创造对象在后进行,在静态方法内不能使用this super因为它们代表从对象中

System.out.println(Chinese.nation);//省略的时Chinese.而不是this.

用static时机:属性是可以被多个对象共享的,不会对象不同而不同的(想static静态的被定义好的以改变都改变所以最好都一样)

操作静态属性的方法一般为静态方法因为这样可不造对象

工具类中的方法例如Arrays(★记住s) Math

★因为静态方法只能调用静态属性所以当一个属性不能共享(即不是静态的)其采用它的方法就必须不是静态的

class Circle { int id; static int initi=1000;//static★ public Circle() { id=initi++;//★ }

}

用(static)final定义的变量为共享的不可改变的常量例如Math.PI

★static的属性一般都有赋值

步骤:写完private 属性后看看谁可以共享就加上static并付初始值,这个静态属性不getset

c语言:

int *p1[10]; 指针数组 包含10 个指向int 类型数据的指针

int (*p2)[10]; 数组指针 加了括号后 *的优先级大于[]所以指针在后数组在前 它指向一个包含10 个int 类型数据的数组 带有数组的指针

  1. int arr[] = { 99, 15, 100, 888, 252 };
  2. ​ int len = sizeof(arr) / sizeof(int); //求数组长度
  3. ​ int i;
  4. for(i=0; i<len; i++){
  5. ​ printf("%d ", (arr+i) ); //(arr+i)等价于arr[i]
  6. ​ }
  7. ​ printf("\n");
  8. return 0;

有一道题没解决

设计模式:套路(大量的实践中优选的代码结构 编程风格,思考方法)

其中的单例设计模式:只存在一个对象实例

要创造单例就必须private构造器为了不让其随便创造对象,因为如此只能在类中创造对象 (private的原因是因为习惯这样然后再用方法调用★但是这个方法必须static即通过类加载因为你无法在其他类中声明对象)

public static void main(String[] args) { Bank b = Bank.getBank(); Bank c = Bank.getBank(); System.out.println(c==b);//true 表示为单例

} } class Bank { private Bank()//想只有一个例子所以。。。 {

}
private static Bank bank = new Bank();//相当于是属性 这个static是因为下面的static才有的 
//static与private是不同的东西
public static Bank getBank()//这里必须static
{
	return bank;
}

}

★:就算是static了也不能直接调用被private的变量

private static Bank bank = null;//相当于是属性 这个static是因为下面的static才有的 
//static与private是不同的东西
public static Bank getBank()//这里必须static
{
	if(bank==null)
	{
		bank=new Bank();
	}
	return bank;

这叫懒汉式用的时候再早,上面叫饿汉式 前者可以延迟对象的创造

饿汉式是线程安全的(用取5000块钱夫妻同时取到来记),在类创建的同时就已经创建好一个静态的对象供系统使用,

看到构造器私有化就想单例

单例运用比较广是因为只对一个对象进行操作方便数据的存取

main:程序入口

String[] str = new String[100];为str数组 String str = new String("")为str

注意★main里面调用此类中不是static的方法时可以早对象,来调用

public static void main public时为了 JVM能调用次方法 static时为了JVM能够类.方法

void 是因为main结束后没有能接住这个返回值的变量了

代码块{}(初始化块)只能用static修饰 静态与非静态 想象因为现在构造器之后所以连public也失去了只能用static 这个静态代码块时随着类的加载而运行(一般类只加载一次所以就执行一次)(想没有名字.可以调用)非静态随对象。。。可执行多次 先考虑代码块在考虑构造器

可有多个代码块 从上到下执行但是一般全都写在一个代码块中

但是代码块用的很少

方法中的属性不能先声明后赋值(记住)

由父及子,静态先行

Bank bank2 = new Bank();//这时是先static的代码块 再 非static 的代码快最后才是构造器

​ new Bank();//这时也是先static的代码块 再 非static 的代码快最后才是构造器

因为创造对象之前要加载类

属性赋值的位置:默认 显示 代码块 构造器 对象.属性

final+类 例如 final class Test 表示这个Test是最终的子类不会再有其子类了 (不需要再次扩充功能)

final+方法也是表示不能重写(即不能扩充功能)

final int I = 6;
I = 7;//不能对最终变量(常量)再次赋值

注意常量都是大写例如Math.PI

final和static不同可以有多个对象不同的final final必须赋值无默认的 方法中不能setFinal因为这样就变了很多次了

public void show(final int N)
{
	System.out.println(N);//这里是调用此方法输入的实参给N,并且只能最后输出N不知道有什么作用

static不能修饰类

static final修饰属性(成为全局常量)(使用最多)和方法

看到大写想常量

public void addOne(final Other o )

{

​ o.i++;//这里可以,因为final的是地址值,内容随便编

}

★ static属性存在于静态域中(=static field(属性))

记static想数组 int[] a a为类 a[i]为共享的属性

构造函数不会被继承,只是被子类调用而已

因为继承所以子类的功能更加明确具体不需要new一个父类的对象这时就可以在父类前加abstract意为造的对象都是子类的对象(★加了就不能造父类对象想象你都抽象了JVM怎么知道你有什么属性可以放在堆中呢)此时构造器是子类来调用才能使用

public abstract void eat();这个是抽象方法(有方法体的都是具体的不抽象) 相当于方法的声明 包含抽象方法的类一定是抽象类,因为这个抽象方法没有方法体无法调用执行,如果不是抽象类就可以new一个对象调用这显然是矛盾的 反之抽象类却可以没有抽象方法 因为子类可以重写

但是当子类继承父类的抽象方法时要么这个子类也变成abstravt的要么就时重写这个方法让abstract的方法变成普通的方法(因为抽象方法不能被调用因为没有方法体)

例子:因为抽象类就等于废了用处为多态 抽象方法是为了父类不写方法体里面的东西(因为父类一般都是一个大类不具体根本写不出来方法体) 让子类重写

package com.atguigu.java1;

class AbstractTest { public static void main(String[] args) { Employee employee =new Mannager("Tom"); employee.work(); Employee employee2=new CommonEmployee("Jenny"); employee2.work(); } } abstract class Employee { String name; int id; double salary; public Employee(String name) { this.name=name; } public abstract void work();//因为不同员工工作不同无法定义父类 记住();结尾不加{} } class Mannager extends Employee//别忘了继承 { double bonus; public Mannager(String name) { super(name); } public void work() { System.out.println("管理员工"); } } class CommonEmployee extends Employee { public void work() { System.out.println("继续奋斗"); } public CommonEmployee(String name) { super(name); } }

}

1.abstract只能方法和类

2.★子类不能重写private方法(因为不可见) static方法 可以想象static是类的而方法的重写是针对对象来书哦的 final方法(不让重写)

int* p 代表p是地址 &p代表p自己的地址 int*知识一个类型代表地址

int *p = NULL 让p指向0地址。 *p = NULL p指向地址的值为0

int a[];

int* p = a;

p+1 表示的是地址往后移 4 个。但并不是所有类型的数组 p+1 都表示往后移 4 个地址。p+1 的本质是移到数组下一个元素的地址

for(i=0;i<5;i++,p++) scanf("%d",p); 本来应该为&p但是p是地址所以不用& 这里是只知道地址再录入值就行了

其实abstract的话就只父类方法的时候用就行了(目前觉得)当不能确定这个父类的方法体时

匿名子类原因父类是abstract

	Animal a = new Animal(){//创建了匿名子类的对象 (对象为a)★本来这里应该是多态的

		@Override
		public void shout() {
			System.out.println("???");
			
		}};
	a.shout();

看到new Animal(){}重写了方法说明这是一个匿名的子类

但是与多态进行比较 Animal a = new 子类();所以后面的两者相等相当于创造了一个匿名子类用这个方法可以不去特意造下面的子类而是直接造了一个匿名子类

模板方法设计模式:固定的模板步骤再父类中写好(易变的为抽象方法),易变的部分用子类重写实现

多态还是可以调用继承父类的方法

package java.util;

public class ATest {

} abstract class Employee { private String name; private int number; private MyDate birthday;//★声明类的对象 public abstract double earnings();//这里格式未记牢

public Employee(String name, int number, MyDate birthday) {
	super();
	this.name = name;
	this.number = number;
	this.birthday = birthday;
}

public String getName() {
	return name;
}
public void setName(String name) {
	this.name = name;
}
public int getNumber() {
	return number;
}
public void setNumber(int number) {
	this.number = number;
}
public MyDate getBirthday() {
	return birthday;
}
public void setBirthday(MyDate birthday) {
	this.birthday = birthday;
}

} class MyDate { private int year,month,day;

public MyDate(int year, int month, int day) {
	super();
	this.year = year;
	this.month = month;
	this.day = day;
}

public void toDataString()
{
	
	System.out.println(year+"年"+month+"月"+day+"日");
}

} class SalariedEmployee extends Employee { private double monthlySalary; public SalariedEmployee(String name,int number, MyDate birthday) { super(name, number, birthday);//一般子类都会调用父类的构造器 }

public void setMonthlySalary(double monthlySalary) {
	this.monthlySalary = monthlySalary;
}



public String toString()//★String
{
	return "员工姓名:"+getName() +" 工号:"+getNumber()+" 生日:"+getBirthday();
}


@Override
public double earnings() {
	
	return monthlySalary;
}

} class HourlyEmployee extends Employee { private double wage,hour;

public HourlyEmployee(String name, int number, MyDate birthday) {
	super(name, number, birthday);
	
}


public void setWage(double wage) {
	this.wage = wage;
}


public void setHour(double hour) {
	this.hour = hour;
}


public double earnings()
{
	return wage*hour;
}

} class PayrollSystem { public static void main(String[] args) { Employee[] employees=new Employee[2];//这句和下面一句本质上没有错但是应该放在main中因为下面一句是赋值

	employees[0]=new SalariedEmployee("马森", 1002, new MyDate(1992, 2, 28));
	employees[1]=new HourlyEmployee("潘雨生", 2001, new MyDate(1991, 5,6));
	//不能employees[0].setMonthlySalary(1000);必须多态
	SalariedEmployee salariedEmployee=(SalariedEmployee)employees[0];
	salariedEmployee.setMonthlySalary(1000);
	HourlyEmployee hourlyEmployee=(HourlyEmployee)employees[1];
	hourlyEmployee.setWage(10);
	hourlyEmployee.setHour(12);
	for(int i =0;i<employees.length;i++)
	{
		System.out.println(employees[i].getClass()+""+employees[i].earnings());

​ ​ } ​ ​ }

}