一.代码块
1.代码块的概念
- 代码块就表示一对大括号,但是定义的位置不同,功能就不同
2.局部代码块
- 格式{ }
- 位置:定义在方法当中
- 作用:限制定义在局部代码块中的变量的作用范围
- 注意:
(2)定义在局部代码块中的变量:作用范围有限、节省内存空间 (局部代码块执行完毕,局部代码块中定义的的变量则被回收)
public class LocalCode1 {//局部代码块:{}定义在方法当中
public static void main(String[] args) {
int i = 10;//作用于主方法中
{//局部代码块
System.out.println(i);//10
int j = 99; //作用于局部代码块中
System.out.println(j);//99
i = 88;
System.out.println(i);//88
}
System.out.println(i);//88
/* System.out.println(j);报错*/
}
}3.构造代码块
- 格式{ }
- 位置:类中,方法外
- 作用:给成员变量进行赋值、 如果多个构造方法具有一部分相同的逻辑,那么这部分相同的逻辑可以写在构造代码块中
- 执行机制:构造代码块在创建对象的同时,JVM主动调用执行,在构造方法之前执行,每次创建对象,只执行一次。
public class Test {
public static void main(String[] args) {
StructureCode2 s1 = new StructureCode2();//调用空参构造
System.out.println(s1.getName());//构造方法被调用了!张三
StructureCode2 s2 = new StructureCode2("李四");//调用全参构造
System.out.println(s2.getName());//构造方法被调用了!李四
}
}
public class StructureCode2 {
private String name;
{//构造代码块
name = "张三";
System.out.println("构造方法被调用了!");//多个构造方法具有一部分相同的逻辑,那么这部分相同的逻辑可以写在构造代码块中
}
public StructureCode2(){
/*System.out.println("构造方法被调用了!");*/
}
public StructureCode2(String name){
/*System.out.println("构造方法被调用了!");*/
this.name = name;
}
public String getName(){
return name;
}
}4.静态代码块
- 格式:static{ }
- 位置:类中,方法外
- 作用:给静态的成员变量进行赋值、 如果一个功能仅仅在类加载进内存时,只执行一次,那么这部分功能就可以写到静态代码块中
- 执行机制:当.class 文件进入到内存时,JVM会主动调用一次静态代码块, 静态代码块在整个类的执行过程中,只执行一次,与创建多少的对象无关。
public class Test {
public static void main(String[] args) {
StaticCode3 s3 = new StaticCode3();
System.out.println(StaticCode3.name);//静态代码块执行了!、构造代码块执行!、构造方法执行了!大美
StaticCode3 s4 = new StaticCode3();//构造代码块执行!、构造方法执行了!
}
}
public class StaticCode3 {
static String name;
static{//静态代码块
System.out.println("静态代码块执行了!");
name = "大美";//给静态成员赋值
}
{//构造代码块
System.out.println("构造代码块执行!");
}
public StaticCode3(){
System.out.println("构造方法执行了!");
}
}5.总结代码块的执行顺序
- 静态代码块(中只执行一次,与创建几次对象无关)---->
- 构造代码块(每次创建对象执行一次)---->
- 构造方法(每次创建对象执行一次)----->
- 局部代码块(方法进栈运行执行)。
6.同步代码块 (多线程的环节,用于解决线程的安全问题)
二.继承
1.继承的概述
- 指类与类之间存在父子关系
- 关键字:继承extends,子 extends 父
- 举例:classA{ } extends classB{ }
2.继承发生的场景
- 子类向上共性抽取为父类
3.继承的优势和弊端
- 继承的优势:
b.提高代码的可维护性(代码维护:代码修改的难易程度)
c.继承为多态提供了前提
- 继承的弊端:
public class Demo01Extends {
public static void main(String[] args) {
//创建一个子类对象teacher
Teacher teacher = new Teacher();
//Teacher类当中虽然什么都没写,但是会继承来自父类的method方法
teacher.work();
//创建一个子类对象assistant
Assistant assistant = new Assistant();
assistant.work();
}
}
public class Employee {
public void work(){
System.out.println("工作!");
}
}
public class Assistant extends Employee {//助教
}
public class Teacher extends Employee{//教师
}4.继承中的注意事项
- 父类中的私有成员(成员变量、成员方法),子类不能继承使用
- 父类中的构造方法,不能被子类继承
5.成员变量在继承中的关系
- 子类可以使用父类中的所有非私有成员变量,父类只能使用本类中定义的成员变量
- 变量的访问具有就近原则,使用变量时,哪个变量离着最近,优先使用哪个变量
- 如果方法中定义了局部变量,优先使用局部变量
- 如果没有局部变量,优先使用类中定义的成员变量
- 如果类中没有成员变量,优先使用父类中的成员变量
- 如果父类中没有成员变量,那么继续找父类的父类,知道找到Object类,仍然没有才报错。
public class TestZiFu {
public static void main(String[] args) {
Fu f = new Fu();//定义一个父类的对象
Zi z = new Zi();//定义一个子类的对象
System.out.println(z.a);// 子类无重名变量a之前输出9,子类有重名变量a之后输出900
System.out.println(z.c);//100
System.out.println(z.d);//200
}
}
public class Fu {
int a = 9;//普通成员变量
private int b = 20;//私有成员变量
static int c = 100;//静态变量
}
public class Zi extends Fu {
//子类可以从父类中继承a=9 ,c两个成员变量
int d = 200;
int a = 900;//子类重新定义变量a,与继承来的变量a重名
}6.方法在继承中的关系
- 子类中可以重写(Override)父类中继承的方法
发生在子父类的继承关系中,子类可以将父类继承来的方法,重新定义
(2)方法重写,必须与父类的方法名相同,参数列表相同,返回值类型相同
(3)子类的方法权限 >= 父类的方法权限
public > protected > [default](什么都不写,默认权限) > private (4)子类在重写了父类的方法之后,调用的是子类重写的方法
(5)重写方法,在方法之上写 @Override 校验
(6)静态方法,只能继承,不能重写
在父子类的继承关系当中,创建子类对象,访问成员方法/的规则
创建的对象是谁,就优先用谁,如果没有则向上找。
public class Demo01ExtendsMethod {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodZi();//子类方法执行!
zi.methodFu();//父类方法执行!
//创建的是new子类对象,所以优先用子类方法
zi.method();//子类重名方法执行
}
}
public class Zi extends Fu {
public void methodZi(){
System.out.println("子类方法执行!");
}
@override
public void method (){
System.out.println("子类重名方法执行");
}
}
public class Fu {
public void methodFu(){
System.out.println("父类方法执行!");
}
public void method (){
System.out.println("父类重名方法执行");
}
}- 说明:什么叫做方法的重载(Overload)?什么叫做方法的重写(Override)?
重写:在子父类继承关系下,子类重写父类中的方法,要求:方法名,参数列表,返回值类型都必须和父类一致,重写的方法权限 >= 父类的权限。
7.构造方法在继承中的关系
- 子类无法继承父类中的构造方法,但是子类的构造方法可以调用父类的构造方法 (构造方法之间调用)
- 子类构造方法的第一行,默认有一个表达式,super();
- 子类构造方法的第一行,也可以手动调用父类的有参构造 super("name");
- 子类必须调用父类构造方法,不写则赠送super(),写了则用写的指定的super调用
- super 表示父类对象的引用 super();
- super(); 表示调用父类的空参构造方法
public class Test {
public static void main(String[] args) {
Fu f = new Fu();//定义一个父类的对象,//我是父类构造!
Zi z = new Zi();//定义一个子类的对象,子类的构造方法可以调用父类的构造方法//我是父类构造!
z.eat();//人需要吃饭
z.getSum(3,5);//x+y=8
z.fun();//静态方法推荐使用类名.调用//去玩
Zi.fun();//去玩
System.out.println(z.name);//大美
}
}
public class Fu {
int a = 9;//普通成员变量
private int b = 20;//私有成员变量
static int c = 100;//静态变量
String name;
//在父类当中定义方法
public void eat(){
System.out.println("人需要吃饭");
}
private void sleep(){
System.out.println("人需要睡觉");
}
public static void fun(){
System.out.println("去玩");
}
public int getSum(int x , int y){
System.out.println("x+y="+(x+y));
return x+y;
}
public Fu(){//父类构造方法
System.out.println("我是父类构造!");
}
public Fu(String name){//父类有参构造
this.name = name;
}
}
public class Zi extends Fu {
//子类可以从父类中继承a=9 ,c两个成员变量
int d = 200;
int a = 900;//子类重新定义变量a,与继承来的变量a重名
//子类从父类中继承到 eat()、getsum()、fun()方法
@Override
public int getSum(int x , int y ){
System.out.println("(x+y)*2="+(x+y)*2);
return (x+y)*2;
}
public Zi(){//子类中构造方法
//第一行默认有一个,super(),调用父类对象的无参构造方法
//父类优先于子类进内存,因为父类中的成员变量和方法,必须先进内存才能让子类使用
//super("大美");//也可以调用父类有参构造
}
}继承中重写应用
public class Phone {
public void call(){
System.out.println("打电话!");
}
public void send(){
System.out.println("发短信!");
}
public void show(){
System.out.println("显示号码" );
}
}
//定义一个新手机,使用老手机作为父类
public class NewPhone extends Phone {
@Override
public void show() {
super.show(); //System.out.println("显示号码");把父类的show方法拿过来重复利用
//子类再来添加更多内容
System.out.println("显示姓名");
System.out.println("显示头像");
}
}
public class Demo01Phone {
public static void main(String[] args) {
Phone phone = new Phone();
phone.call();
phone.send();
phone.show();
System.out.println("=================");
NewPhone newPhone = new NewPhone();
newPhone.call();
newPhone.send();
newPhone.show();
}
}
8.super关键字的使用
- super:关键字,表示父类对象的使用
- 在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在子类的构造方法中,访问父类的构造方法super(实参);
- this:关键字,表示子类对象的引用
- 在本类的成员方法中,访问本类的成员变量
- 在本类的成员方法中,访问本类的另一个成员方法
- 在本类的构造方法中,访问本类的另一个构造方法this(实参);
- 说明:super();或this();二者只能选择一个
public class Demo01Constructor {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
public class Fu {
public Fu(){
System.out.println("父类无参构造");
}
public Fu(int num){
System.out.println("父类有参方法");
}
}
public class Zi extends Fu {
public Zi(){
//super();//在调用父类无参构造方法 若不写 编译器赠送
super(20);
System.out.println("子类构造方法!");
}
public void method(){
//super();//错误写法,只有子类构造方法才能调用父类构造方法
}
} 9.区分子类方法中重名的三种
- 局部变量:直接写
- 本类的成员变量:this.成员变量名
- 父类的成员变量:super.成员变量名
public class Demo01ExtendsField {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
public class Fu {
int num = 10;
}
public class Zi extends Fu{
int num = 20;
public void method(){
int num = 30;
System.out.println(num);//30 局部变量
System.out.println(this.num);//20 本类的成员变量
System.out.println(super.num);//10,父类的成员变量
}
} 10.说明:在父子类的继承关系中,如果成员变量重名,则创建子类对象时,有两种方式访问
* 直接通过子类对象访问成员变量:
* 等号左边是谁,就优先用谁,没有则向上找
* 间接通过成员方法访问成员变量:
* 该方法属于谁,该方法在哪定义的,没有则向上找
public class Demo01ExtendsField {
public static void main(String[] args) {
Fu fu = new Fu();
System.out.println(fu.numFu);//只能用父类的东西,没有任何子类内容
Zi zi = new Zi();
System.out.println(zi.numFu);//子类没有,向上找父类中的
System.out.println(zi.numzi);//子类有
System.out.println("=================");
//间接通过成员方法访问成员变量
System.out.println(zi.num);//父子类发生重名,等号左边是谁,就优先用谁,优先子类
zi.methodzi();//这个方法是子类的,优先用子类的,优先用子类的
zi.methodFu();//这个方法是在父类当中定义的,属于父类
}
}11.继承的特点
- java语言是单继承的 一个类的直接父类只能有唯一一个
- java可以多级继承
- 一个子类的直接父类是唯一的,但是一个父类可以拥有多个子类。
双色球案例
系统生成双色球:
6颗红球(33选1) 1颗蓝球(16选1),要求6个红球号码不重复
客户购买双色球:
要求客户键盘输入,6个红球号码(1-33),1个蓝球号码(1-66)
验证客户购买后是否中奖
(1)6个红球和1个蓝球全部买中,一等奖, 1000万
(2)买中1个蓝球,3-5个红球,二等奖,500万
(3)买中一个蓝球,1-2个红球,三等奖,100万
(4)买中一个蓝球,没买中红球,四等奖,50万
(5)剩下情况没中奖
分析:
1.系统生成,Random
2.先自动生成一个蓝球,16选1 --nextInt(16)+1
3.将6个红球放至数组中, --nextInt(33)+1
4.使用循环,6个随机数放至int[6],数组中的元素不重复 一个int[33]索引
5.客户通过键盘录入6个红球,范围1-33
6.客户键盘录入1个蓝球,范围1-16
7.验证中奖
匹配系统6红球与客户输入的6个红球几个相同的,计数
匹配系统1蓝球与客户输入的1个蓝球
import java.util.Arrays;
import java.util.Random;
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
//1.系统生成球
Random r = new Random();
int sysBlue = r.nextInt(16)+1;//生成1个蓝球
int[] sysRed = new int[6];
int[] arr = new int[33];
for (int i = 0; i < arr.length; i++) {
arr[i] = i+1;
}
for (int i = 0; i < sysRed.length; i++) {
int count = r.nextInt(33)+1;
if(arr[count-1] == 0)
i--;
else {
arr[count-1] = 0;
sysRed[i] = count;
}
}
Scanner sc = new Scanner(System.in);
int[] scRed = new int[6];
for (int i = 0; i < scRed.length; i++) {
System.out.println("请输入第"+(i+1)+"个红球编号:");
scRed[i] = sc.nextInt();
if(scRed[i]>33 || scRed[i]<1){
System.out.println("输入有误,请重新输入");
i--;
}
}
System.out.println("红球输入完毕!");
System.out.println("请输入1个蓝球:");
int scBlue;
while(true) {
scBlue = sc.nextInt();
if(scBlue>16 || scBlue<1){
System.out.println("蓝球输入有误,请重新输入:");
}else
break;
}
System.out.println("蓝球输入完毕!");
System.out.println("系统生成的红球为:"+ Arrays.toString(sysRed));
System.out.println("系统生成的蓝球为:"+ sysBlue+'\n');
System.out.println("您输入的红球为:"+ Arrays.toString(scRed)+'\n'+"蓝球为:"+scBlue);
int count = 0;
boolean flag = false;
for (int i = 0; i < 6; i++) {
if(sysRed[i] == scRed[i])
count++;
}
if(sysBlue == scBlue)
flag = true;
if(flag == true) {//买中蓝球
switch (count) {
case 6:
System.out.println("恭喜你,一等奖:1000万!");
break;
case 5: case 4: case 3:
System.out.println("恭喜你,二等奖:500万!");
break;
case 2: case 1:
System.out.println("恭喜你,三等奖: 100万!");
break;
default:
System.out.println("恭喜你,四等奖:50万!");
}
}else{
System.out.println("很抱歉,没有中奖");
}
}
}