21.2.8
Java基础- - - - - - 匿名对象
匿名对象
- 匿名对象:我们创建的对象,没显式的赋给一个变量名。即为匿名对象
- 特点:匿名对象只能调用一次。
- 举例:
new Phone().sendEmail();
new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice();//0.0
- 应用场景:
PhoneMall mall = new PhoneMall();
//匿名对象的使用
mall.show(new Phone());
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
Java基础- - - - - - 可变个数形参
- 格式:
JDK5.0以前:数据类型[] 变量名
public void show(String[] strs){
}
JDK5.0以后:数据类型 ... 变量名
public void show(String ... strs){
}
注意:同一个类中两则不能共存
- 可变个数形参在方法的形参中,必须声明在末尾
- 可变个数形参在方法的形参中,最多只能声明一个可变形参
Java基础- - - - - - 方法参数的值传递机制
-
规则:
- 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
- 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
-
推广:
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
-
注意点1:
public class ValueTransferTest1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("m = " + m + ", n = " + n);
//交换
ValueTransferTest1 test = new ValueTransferTest1();
test.swap(m, n);
System.out.println("m = " + m + ", n = " + n);
}
public void swap(int m,int n){
int temp = m ;
m = n;
n = temp;
}
}
编译结果:没换成功
原因:交换的是·swap方法中的值,main方法中并没有交换
- 注意点2:
public class ValueTransferTest2 {
public static void main(String[] args) {
Data data = new Data();
data.m = 10;
data.n = 20;
System.out.println("m = " + data.m + ", n = " + data.n);
ValueTransferTest2 test = new ValueTransferTest2();
test.swap(data);
System.out.println("m = " + data.m + ", n = " + data.n);
}
public void swap(Data data){
int temp = data.m;
data.m = data.n;
data.n = temp;
}
}
class Data{
int m;
int n;
}
编译结果:换成功
原因:参数是引用数据类型,传递的是地址值,指向同一个对象
- 练习:
答案:15,0,20
21.2.9
Java基础- - - - - - 递归方法的使用
- 1.定义:一个方法体内调用它自身。
- 2.如何理解递归方法?
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无须循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
- 举例:
例1:计算1-n之间所有自然数的和
public int getSum(int n) {
if(n == 1) {
return 1;
}else {
return n+ getSum(n-1);
}
}
例2:计算1-n之间所有自然数的乘积:n!
public int getSum1(int n) {
if (n == 1) {
return 1;
} else {
return n * getSum1(n - 1);
}
}
Java基础- - - - - - Java规定的四种权限修饰符
- 4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类
- 修饰类的话,只能使用:缺省、public
1:缺省
class Person{
}
2:public
publlic class Demo{
}
Java基础- - - - - - UML类图
Java基础- - - - - - this关键字
- this调用属性、方法
- this调用构造器
- 使用"this(形参列表)"方式
- 构造器中不能通过"this(形参列表)"方式调用自己
- 构造器中不能通过"this(形参列表)"方式调用自己
- 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器
Java基础- - - - - - Eclipse中的快捷键:
- 1.补全代码的声明:alt + /
- 2.快速修复: ctrl + 1
- 3.批量导包:ctrl + shift + o
- 4.使用单行注释:ctrl + /
- 5.使用多行注释: ctrl + shift + /
- 6.取消多行注释:ctrl + shift + \
- 7.复制指定行的代码:ctrl + alt + down 或 ctrl + alt + up
- 8.删除指定行的代码:ctrl + d
- 9.上下移动代码:alt + up 或 alt + down
- 10.切换到下一行代码空位:shift + enter
- 11.切换到上一行代码空位:ctrl + shift + enter
- 12.如何查看源码:ctrl + 选中指定的结构 或 ctrl + shift + t
- 13.退回到前一个编辑的页面:alt + left
- 14.进入到下一个编辑的页面(针对于上面那条来说的):alt + right
- 15.光标选中指定的类,查看继承树结构:ctrl + t
- 16.复制代码: ctrl + c
- 17.撤销: ctrl + z
- 18.反撤销: ctrl + y
- 19.剪切:ctrl + x
- 20.粘贴:ctrl + v
- 21.保存: ctrl + s
- 22.全选:ctrl + a
- 23.格式化代码: ctrl + shift + f
- 24.选中数行,整体往后移动:tab
- 25.选中数行,整体往前移动:shift + tab
- 26.在当前类中,显示类结构,并支持搜索指定的方法、属性等:ctrl + o
- 27.批量修改指定的变量名、方法名、类名等:alt + shift + r
- 28.选中的结构的大小写的切换:变成大写: ctrl + shift + x
- 29.选中的结构的大小写的切换:变成小写:ctrl + shift + y
- 30.调出生成getter/setter/构造器等结构: alt + shift + s
- 31.显示当前选择资源(工程 or 文件)的属性:alt + enter
- 32.快速查找:参照选中的Word快速定位到下一个 :ctrl + k
- 33.关闭当前窗口:ctrl + w
- 34.关闭所有的窗口:ctrl + shift + w
- 35.查看指定的结构使用过的地方:ctrl + alt + g
- 36.查找与替换:ctrl + f
- 37.最大化当前的View:ctrl + m
- 38.直接定位到当前行的首位:home
- 39.直接定位到当前行的末位:end
21.2.10
Java基础- - - - - - 练习题(注意点)
1:注意方法的调用次序,以及要画图
public class Test{
public static void leftshift(int i, int j){
i+=j;
System.out.println(i); //6
}
public static void main(String args[]){
int i = 4, j = 2;
leftshift(i, j);
System.out.println(i); //4
}
}
答案:
4. 和leftShift函数没关系。
- List item
21.2.12
Java基础- - - - - - Eclipse_Debug调试
1:Debug不能打开界面问题解决
Bug解决|Eclipse点击Debug没有弹出Debug视图
2:Debug界面Variables显示问题
Window—Show view----other----Debug
3:如何调试
- 设置断点(注意:可以设置多个断点)
- debug as java application
- 常用操作
Java基础- - - - - - 多态性(向下转型)
- 1:理解:Man man = new Man();
有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性和方法。子类特有的属性和方法不能调用。?如何才能调用子类特的属性和方法?使用向下转型。 - 2:如何实现向下转型:
使用强制类型转换符:()
Person p2 = new Man();
//如何才能调用子类特有的属性和方法?
//向下转型:使用强制类型转换符。
Man m1 = (Man)p2;
//强转后,就可以调用子类特有的方法
m1.earnMoney();
m1.isSmoking = true;
- 3:使用时的注意点:
① 使用强转时,可能出现ClassCastException的异常。
② 为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。 - 4:instanceof的使用:
① a instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false。
② 如果 a instanceof A返回true,则 a instanceof B也返回true.其中,类B是类A的父类。
③ 要求a所属的类与类A必须是子类和父类的关系,否则编译错误。
if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
w1.goShopping();
System.out.println("******Woman******");
}
if(p2 instanceof Man){
Man m2 = (Man)p2;
m2.earnMoney();
System.out.println("******Man******");
}
Java基础- - - - - - 多态性(实例变量例子)
- 1.若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中:编译看左边,运行看右边
- 2.对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量:编译运行都看左边
举例:
Java基础- - - - - - 多态性(虚拟方法调用)
Java基础- - - - - - 父类未定义空参构造器,子类…
- 父类在定义了有参构造器的同时,未显式定义空参构造器的情况下。
在定义子类时,由于没有空参构造器继承,在不定义有参构造器的情况下,必须显式的定义一个空参构造器,否则会编译错误。
Java基础- - - - - - 多态性(子父类中int… arr和int[] arr)
Java基础- - - - - - java.lang.Object类常用方法(equals()、toString())
equals()的使用:
-
是一个方法,而非运算符
-
只能适用于引用数据类型
-
Object类中equals()的定义:
public boolean equals(Object obj) {
return (this == obj);
}
说明:Object类中定义的equals()和==的作用是相同的:
比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写.
- 重写的原则:==比较两个对象的实体内容==是否相同
- 注意:像String、Date、File、包装类等都重写了Object类中的equals()方法
如何手动重写equals()
package com.atguigu.java1;
public class Customer {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Customer() {
super();
}
public Customer(String name, int age) {
super();
this.name = name;
this.age = age;
}
//重写的原则:比较两个对象的实体内容(此举例即:name和age)是否相同
public boolean equals1(Object obj) {
//如果当前对象和形参引用地址值一样,直接返回true
if (this == obj) {
return true;
}
//判断形参obj是否是Customer的实例
if(obj instanceof Customer){
//如果obj是Customer的实例,将obj强转成Customer类型
Customer cust = (Customer)obj;
//比较两个对象的每个属性是否都相同
//此例中age是基本数据类型,故用==比较,但name是引用数据类型,需要用equals()比较
if(this.age == cust.age && this.name.equals(cust.name)){
return true;
}else{
return false;
}
// //或
// return this.age == cust.age && this.name.equals(cust.name);
}else{
return false;
}
}
如何自动重写equals()
Source---->Generate HashCode and equals---->
重写equals()练习
/*
* 编写Order类,有int型的orderId,String型的orderName,
* 相应的getter()和setter()方法,两个参数的构造器,
* 重写父类的equals()方法:public boolean equals(Object obj),
* 并判断测试类中创建的两个对象是否相等。
*/
public class OrderTest {
public static void main(String[] args) {
Order o1 = new Order(23, "Tom");
Order o2 = new Order(23, "Tom");
System.out.println(o1 == o2);//false
System.out.println(o1.equals(o2));//true(重写过,故比较的是实体内容 )
}
}
class Order{
private int orderId;
private 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;
}
@Override
public boolean equals(Object obj) {
if(this == obj) {
return true;
}
if(obj instanceof Order) {
Order order = (Order)obj;
if(this.orderId == order.orderId && this.orderName.equals(order.orderName)) {
return true;
}else {
return false;
}
}
return false;
}
}
public class MyDateTest {
public static void main(String[] args) {
MyDate m1 = new MyDate(14, 3, 1976);
MyDate m2 = new MyDate(14, 3, 1976);
if (m1 == m2) {
System.out.println("m1==m2");
} else {
System.out.println("m1!=m2"); // m1 != m2
}
if (m1.equals(m2)) {
System.out.println("m1 is equal to m2");// m1 is equal to m2
} else {
System.out.println("m1 is not equal to m2");
}
}
}
class MyDate{
private int day;
private int month;
private int year;
public MyDate(int day, int month, int year) {
super();
this.day = day;
this.month = month;
this.year = year;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public boolean equals(Object obj) {
if(this == obj){
return true;
}
if(obj instanceof MyDate){
MyDate myDate = (MyDate)obj;
return this.day == myDate.day && this.month == myDate.month &&
this.year == myDate.year;
}
return false;
}
//自动重写
// @Override
// public boolean equals(Object obj) {
// if (this == obj)
// return true;
// if (obj == null)
// return false;
// if (getClass() != obj.getClass())
// return false;
// MyDate other = (MyDate) obj;
// if (day != other.day)
// return false;
// if (month != other.month)
// return false;
// if (year != other.year)
// return false;
// return true;
// }
}
toString()的使用:
- Object类中toString()的定义:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 当我们输出一个对象的引用时,实际上就是调用当前对象的toString()
- 像String、Date、File、包装类等都重写了Object类中的toString()方法。使得在调用对象的toString()时,返回"实体内容"信息
- 自定义类也可以重写toString()方法,当调用此方法时,返回对象的"实体内容"
- 采用自动重写实现即可
21.2.13
c
为了使基本数据类型的变量具有类的特征,引入包装类
基本数据类型与对应的包装类:
基本数据类型、包装类、String三者之间的相互转换
- 基本数据类型<—>包装类:JDK 5.0 新特性:自动装箱 与自动拆箱
@Test
public void test3(){
//自动装箱:基本数据类型 --->包装类
int num2 = 10;
Integer in1 = num2;//自动装箱
boolean b1 = true;
Boolean b2 = b1;//自动装箱
//自动拆箱:包装类--->基本数据类型
System.out.println(in1.toString());
int num3 = in1;//自动拆箱
}
- 基本数据类型、包装类—>String:
- 调用String重载的valueOf(Xxx xxx)
- 连接运算
@Test
public void test4(){
int num1 = 10;
//方式1:连接运算
String str1 = num1 + "";
//方式2:调用String的valueOf(Xxx xxx)
float f1 = 12.3f;
String str2 = String.valueOf(f1);//"12.3"
Double d1 = new Double(12.4);
String str3 = String.valueOf(d1);
System.out.println(str2);
System.out.println(str3);//"12.4"
}
String—>基本数据类型、包装类:调用包装类的parseXxx(String s)
@Test
public void test5(){
String str1 = "123";
//错误的情况:
// int num1 = (int)str1;
// Integer in1 = (Integer)str1;
//可能会报NumberFormatException
int num2 = Integer.parseInt(str1);
System.out.println(num2 + 1);
String str2 = "true";
boolean b1 = Boolean.parseBoolean(str2);
System.out.println(b1);//true
String str3 = "true1";
boolean b2 = Boolean.parseBoolean(str3);
System.out.println(b2);//false(非true就是false)
}
Java基础- - - - - - 包装类(面试题:)
题一:知识点(编译时类型相同,自动类型提升)
解题:
题二:知识点(Integer包装类中-128~127范围的整数地址在相同)
解题
Java基础- - - - - - 包装类(练习题)
import java.util.Scanner;
import java.util.Vector;
/*
* 利用Vector代替数组处理:从键盘读入学生成绩(以负数代表输入结束),找出最高分,并输出学生成绩等级。
提示:数组一旦创建,长度就固定不变,所以在创建数组前就需要知道它的长度。
而向量类java.util.Vector可以根据需要动态伸缩。
创建Vector对象:Vector v=new Vector();
给向量添加元素:v.addElement(Object obj); //obj必须是对象
取出向量中的元素:Object obj=v.elementAt(0);
注意第一个元素的下标是0,返回值是Object类型的。
计算向量的长度:v.size();
若与最高分相差10分内:A等;20分内:B等;
30分内:C等;其它:D等
*
*
*
*
*/
public class ScoreTest {
public static void main(String[] args) {
//1.实例化Scanner,用于从键盘获取学生成绩
Scanner scan = new Scanner(System.in);
//2.创建Vector对象:Vector v=new Vector();相当于原来的数组
Vector v = new Vector();
//3.通过for(;;)或while(true)方式,给Vector中添加数组
int maxScore = 0;
for(;;){
System.out.println("请输入学生成绩(以负数代表输入结束)");
int score = scan.nextInt();
//3.2 当输入是负数时,跳出循环
if(score < 0){
break;
}
if(score > 100){
System.out.println("输入的数据非法,请重新输入");
continue;
}
//3.1 添加操作::v.addElement(Object obj)
//jdk5.0之前:
// Integer inScore = new Integer(score);
// v.addElement(inScore);//多态
//jdk5.0之后:
v.addElement(score);//自动装箱
//4.获取学生成绩的最大值
if(maxScore < score){
maxScore = score;
}
}
//5.遍历Vector,得到每个学生的成绩,并与最大成绩比较,得到每个学生的等级。
char level;
for(int i = 0;i < v.size();i++){
Object obj = v.elementAt(i);
//jdk 5.0之前:
// Integer inScore = (Integer)obj;
// int score = inScore.intValue();
//jdk 5.0之后:
int score = (int)obj;
if(maxScore - score <= 10){
level = 'A';
}else if(maxScore - score <= 20){
level = 'B';
}else if(maxScore - score <= 30){
level = 'C';
}else{
level = 'D';
}
System.out.println("student-" + i + " score is " + score + ",level is " + level);
}
}
}
知识点;
- continue:结束本次循环,会重新开始下一次循环
- break;结束循环。
Java基础- - - - - - 重写规则(返回值类型)
返回值类型:
- 父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void
- 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类
- 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
21.2.14
Java基础- - - - - - 构造器调用 ( “父先行”)
当调用子类构造器来初始化子类对象时,父类构造器总会在子类构造器之前先执行,不仅如此,执行父类构造器时,系统会再次上溯执行其父类构造器…以此类推,创建任何Java对象,最先执行的总是Java,lang,Object类的构造器
Java基础- - - - - - 单例设计模式
饿汉式:提前造好对象
public class SingletonTest1{
public static void main(String[] args){
Bank bank1 = Bank.getInstance();
Bank bank2 = Bank.getInstance();
System.out.println(bank1 == bank2);//true
}
}
//饿汉式
class Bank{
//1.私有化类的构造器
private Bank(){
}
//2.内部创建类的对象,要求此对象必须声明为静态的
private static Bank instance = new Bank();
//3.提供公共的静态方法,返回类的对象
public static Bank getInstance() {
return instance;
}
}
懒汉式:什么时候用什么时候造对象
public class SingletonTest2{
public static void main(String[] args){
Order order1 = Order.getInstance();
Order order2 = Order.getInstance();
System.out.println(order1 == order2);//true
}
}
//懒汉式
class Order{
//1.私有化类的构造器
private Order(){
}
//声明当前类的对象,没有初始化,此对象必须声明为static
private static Order instance = null;
//3.声明public、static的返回当前类对象的方法
public static Order getInstance(){
//是null说明还没有创建对象
if(instance == null){
instance = new Order();
}
return instance;
}
}
两者对比:
- 饿汉式:坏处,对象加载过长。好处,线程安全的
- 懒汉式:好出,延迟对象的创建。目前这种写法,线程是不安全的
Java基础- - - - - - 实例化子类对象时,涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序(由父及子,静态先行)
# 21.2.15
Java基础- - - - - - 自动获取当前的时间(年、月、日)
//获取当前月份
Calendar calendar = Calendar.getInstance();
int month = calendar.get(Calendar.MONTH);//注意:1月份是0
//获取当前年份
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
System.out.println(year);
//获取本月天数(今日是本月的第几天)
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println(day);
//获取本周天数(今日是本周的第几天)
Calendar calendar = Calendar.getInstance();
int day = calendar.get(Calendar.DAY_OF_WEEK);
System.out.println(day);
Java基础- - - - - - 匿名子类的对象、匿名子类的匿名对象
abstract class Creature{
public abstract void breath();
}
abstract class Person extends Creature{
String name;
int age;
public Person(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
//抽象方法
public abstract void eat();
public void walk(){
System.out.println("人走路");
}
}
//继承Person抽象类,并实现了抽象方法
class Student extends Person{
public Student(String name,int age){
super(name,age);
}
public Student(){
}
public void eat(){
System.out.println("学生多吃有营养的食物");
}
@Override
public void breath() {
System.out.println("学生应该呼吸新鲜的没有雾霾的空气");
}
}
public class PersonTest {
public static void main(String[] args) {
method(new Student());//匿名对象
Worker worker = new Worker();
method1(worker);//非匿名的类非匿名的对象
method1(new Worker());//非匿名的类匿名的对象
System.out.println("********************");
//创建了一匿名子类的对象:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);
System.out.println("********************");
//创建匿名子类的匿名对象
method1(new Person(){
@Override
public void eat() {
System.out.println("吃好吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸新鲜空气");
}
});
}
public static void method1(Person p){
p.eat();
p.breath();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
Java基础- - - - - - 接口的匿名实现类的非匿名对象、接口的匿名实现类的匿名对象
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
//1.创建了接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
com.transferData(flash);
//2. 创建了接口的非匿名实现类的匿名对象
com.transferData(new Printer());
//3. 创建了接口的匿名实现类的非匿名对象
USB phone = new USB(){
@Override
public void start() {
System.out.println("手机开始工作");
}
@Override
public void stop() {
System.out.println("手机结束工作");
}
};
com.transferData(phone);
//4. 创建了接口的匿名实现类的匿名对象
com.transferData(new USB(){
@Override
public void start() {
System.out.println("mp3开始工作");
}
@Override
public void stop() {
System.out.println("mp3结束工作");
}
});
}
}
class Computer{
public void transferData(USB usb){//USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//常量:定义了长、宽、最大最小的传输速度等
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class Printer implements USB{
@Override
public void start() {
System.out.println("打印机开启工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
Java基础- - - - - - 代理模式(代理类、被代理类)
Java基础- - - - - - Java8中关于接口的新规范
- JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
- 接口中定义的静态方法,只能通过接口来调用
public interface CompareA {
//静态方法
public static void method1(){
System.out.println("CompareA:北京");
}
//默认方法
public default void method2(){
System.out.println("CompareA:上海");
}
default void method3(){//public 可省略
System.out.println("CompareA:上海");
}
}
public class SubClassTest {
public static void main(String[] args) {
//知识点1:接口中定义的静态方法,只能通过接口来调用。
CompareA.method1();
}
}
- 通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
public class SubClassTest {
public static void main(String[] args) {
SubClass s = new SubClass();
//知识点2:通过实现类的对象,可以调用接口中的默认方法。
//如果实现类重写了接口中的默认方法,调用时,仍然调用的是重写以后的方法
s.method2();
}
- 如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,那么子类在没重写此方法的情况下,默认调用的是父类中的同名同参数的方法。–>类优先原则
- 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,
- 那么在实现类没重写此方法的情况下,报错。–>接口冲突。
- 这就需要我们必须在实现类中重写此方法
- 在子类(或实现类)的方法中调用父类、接口中被重写的方法
public void myMethod(){
method3();//调用自己定义的重写的方法
super.method3();//调用的是父类中声明的
//调用接口中的默认方法
CompareA.super.method3();
CompareB.super.method3();
}
21.2.16
Java基础- - - - - - 静态方法(this关键字、super关键字)
- 在静态的方法内,不能使用this关键字、super关键字,因为不需要实例就可以访问static方法,
Java基础- - - - - - 代码块(静态、非静态)
代码块的作用:
- 用来初始化类、对象的信息
静态代码块:为静态属性赋值
- 内部可以输出语句
- 随着类的加载而执行,而且只执行一次
- 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
- 静态代码块的执行要优先于非静态代码块的执行
- 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构
非静态代码块:为非静态属性赋值
- 内部可以输出语句
- 随着对象的创建而执行
- 每创建一个对象,就执行一次非静态代码块
- 作用:可以在创建对象时,对对象的属性等进行初始化
- 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
- 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法
Java基础- - - - - - 内部类(成员内部类、局部内部类在编译以后,都会生成字节码文件)
- 成员内部类:外部类$内部类名.class
- 局部内部类:外部类$数字 内部类名.class
Java基础- - - - - - final(修饰方法)
- 注意:使用final修饰一个private访问权限的方法,依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法
Java基础- - - - - - abstract(注意)
用来abstract修饰:属性、构造器等结构
- abstract不能用来修饰属性、构造器、私方法、静态方法、final的方法、final的类
Java基础- - - - - - 继承(子类调用构造器)
- (1)如果子类构造器中,没有写super()或super(实参列表)语句,那么默认就是调用父类“无参构造”
- (2)子类的构造器中,也可以手动调用父类的构造器,super()或super(实参列表)
- (3)当父类没有无参构造时,子类的构造中必须手动调用父类的有参构造super(实参列表)
- (4)super()或super(实参列表)它必须在子类构造器的首行
21.2.17
JavaDug- - - - - - Exception in thread “main” java.lang.Error: Unresolved compilation problem
- 错误的原因是因为代码中没有指定package
JavaDug- - - - - - NoClassDefFoundError原因
NoClassDefFoundError和ClassNotFoundException
在java开发的过程经常会遇到这两个异常并且时常会产生混淆,为了便于区别,特作如下总结:
- 相似点
NoClassDefFoundError和ClassNotFoundException异常出现原因都是加载不到类导致,但是两者确有本质的区别。 - 不同点
ClassNotfoundException是在编译过程中JVM加载不到类或者找不到类引起;
NoClassDefError是在运行时JVM加载不到类或者找不到类引起;
NoClassDefFoundError错误发生原因
NoClassDefFoundError错误发生原因与Java虚拟机的工作原理相关,下面简单介绍一下JVM的类加载机制,其中类加载器的三个机制为委托、单一性、可见性。
- 委托:指加载一个类的请求交给父类加载器,若父类加载器不可以找到或者加载到,再加载这个类;
- 单一性:指子类加载器不会再次加载父类加载器已经加载过的类 ;
- 可见性:子类加载器可以看见父类加载器加载的所有类,而父类加载器不可以看到子类加载器加载的类
JVM的委托机制决定了类加载器只加载一次,子类加载器不会再加载父类加载器已经加载过的类,因此在一些特定条件下就会出现编译时可以加载到类,运行时不可以加载到类,这时候就会出现java.lang.NoClassDefFoundError异常
Java基础- - - - - - 多线程(Thread的setName()方法使用注意)
- 创建线程的时候设置名字
- 注意:
Java基础- - - - - - 多线程(Thread的yield()方法使用注意)
- JDK中注释,向调度程序暗示(hint)当前线程愿意让出CPU,调度程序可以忽略此暗示。也就是说当前线程可能根本就没有让出CPU,线程一直在运行。
- 注意:测试程序电脑是否是多核CPU也会影响结果