静态内部类
-
静态内部类对象可以不依赖于外部类对象,直接创建
-
静态内部类中,只能直接访问外部类的静态方法,如果需要调用非静态方法,可以通过对象实例
new Person().eat();
-
静态内部类中,只能直接访问外部类的静态成员,如果需要调用非静态成员,可以通过对象实例
return new Person().age+"心脏在跳动";
-
获取静态内部类对象实例,可以不依赖于外部类对象
Person.Heart myHeart=new Person.Heart();
-
可以通过外部类.内部类.静态成员的方式,访问内部类中的静态成员
-
当内部类属性于外部类属性同名时,默认直接调用内部类中的成员
-
如果需要访问外部类中的静态属性,则可以通过 外部类.属性 的方式
-
如果需要访问外部类中的非静态属性,则可以通过 new 外部类().属性 的方式
方法内部类
-
定义在外部类方法中的内部类,也称为局部内部类
-
定义在方法内部,作用范围也在方法内
-
和方法内部成员使用规则一样,class前面不可以添加public、private、protected、static
-
类中不能包含静态成员
-
类中可以包含final、abstract修饰的成员
匿名内部类
-
匿名内部类没有类型名称、实例对象名称
-
编译后的文件命名:外部类$数字.class
-
无法使用private、public、protected、abstract、static修饰
-
无法编写构造方法,可以添加构造代码块
-
不能出现静态成员
-
匿名内部类可以实现接口也可以继承父类,但是不可兼得
-
适用场景:
-
只用到类的一个实例
-
类在定义后马上用到
-
给类命名并不会导致代码更容易被理解
-
//匿名内部类 test.getRead(new Person() { @Override public void read() { System.out.println("男生"); } }); test.getRead(new Person() { @Override public void read() { System.out.println("女生"); } });
拼图小游戏
-
GUI:图形用户接口,是指采用图形化的方式显示操作界面
AWT包、Swing包
-
主界面分析
JFrame:最外层的窗体
JMenuBar:最上层的菜单
JLabel:管理文字和图片的容器
-
事件
可以被组件识别的操作
当你对组件干了某件事情之后,就会执行相应的代码
事件源:按钮 图片...
事件:某些操作,如:鼠标单击、鼠标划入...
绑定监听:当事件源上发生了某个事件,则执行某段代码
-
KeyListener:键盘监听
-
MouseListener:鼠标监听
-
ActionListener:动作监听
-
package com.itheima.ui; import com.itheima.ui.GameJFrame; import com.itheima.ui.LoginJFrame; import com.itheima.ui.RegisterJFrame; public class App { public static void main(String[] args) { // 程序的启动入口 //如果我们想要开启一个界面,就创建谁的对象 new LoginJFrame(); // new RegisterJFrame(); // new GameJFrame(); } }
package com.itheima.ui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.File; import java.util.Random; import javax.swing.ImageIcon; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.border.BevelBorder; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.Clip; public class GameJFrame extends JFrame implements KeyListener,ActionListener{ //JFrame:界面,窗体 //规定:GameJFrame这个界面就是游戏的主界面 //创建一个二维数组:用来管理图片,加载图片时会根据二维数组中的数据进行加载 int [][] data=new int[4][4]; //记录空白方块的位置 int x=0; int y=0; //记录当前展示图片的路径 String path="image/animal/animal3/"; //判断胜利 int[][] win= { {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,0} }; // 标志位,表示游戏是否胜利 private boolean gameWon = false; //计步器 int step=0; private Clip c; private AudioInputStream ais; //添加一个标志,用于跟踪音乐的播放状态 private boolean musicPlaying = true; //创建选项下面的条目对象 JMenuItem girl = new JMenuItem("我们"); JMenuItem animal = new JMenuItem("动物"); JMenuItem sport = new JMenuItem("运动"); JMenuItem pauseMusicItem = new JMenuItem("暂停音乐"); JMenuItem replayItem=new JMenuItem("重新游戏"); JMenuItem reLoginItem=new JMenuItem("重新登录"); JMenuItem closeItem=new JMenuItem("关闭游戏"); JMenuItem accountItem=new JMenuItem("联系作者"); public GameJFrame() { //初始化界面 initJFrame(); //初始化菜单 initJMenuBar(); //初始化数据(打乱) initData(); //初始化图片 initImage(); this.setVisible(true);//把窗口显示出来,默认false不显示 } //初始化数据 private void initData() { //定义一个一维数组 int[] tempArr= {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; //打乱顺序 //遍历数组,得到每一个元素,拿着每一个元素跟随机索引上的数据进行交换 Random r=new Random(); for(int i=0;i<tempArr.length;i++) { //获取随机索引 int index =r.nextInt(tempArr.length); //拿着遍历到的数据跟索引上的数据进行交换 int temp=tempArr[i]; tempArr[i]=tempArr[index]; tempArr[index]=temp; } //给二维数组添加数据 for(int i=0;i<tempArr.length;i++) { if(tempArr[i]==0) { x=i/4; y=i%4; } data[i/4][i%4]=tempArr[i]; } } //初始化图片 //添加图片时需要按照二维数组中管理的数据添加图片 private void initImage() { //清空原本出现的所有图片 this.getContentPane().removeAll(); if(victory()) { //显示胜利图标 JLabel winLabel=new JLabel(new ImageIcon("image/win.png")); winLabel.setBounds(203,283,197,73); this.getContentPane().add(winLabel); } JLabel stepCount=new JLabel("步数"+step); stepCount.setBounds(50,30,100,20); this.getContentPane().add(stepCount); //先加载的图片在上方,后加载的图片在下面 //外循环----四行 for(int i=0;i<4;i++) { //内循环---在一行添加四张图片 for(int j=0;j<4;j++) { //获取加载图片的序号 int num=data[i][j]; //创建一个JLabel对象 JLabel jLabel=new JLabel(new ImageIcon(path+num+".jpg")); //指定图片位置 jLabel.setBounds(105*j+83,105*i+134,105,105); //给图片添加边框 //0:让图片凸起来 //1:让图片凹下去 jLabel.setBorder(new BevelBorder(1)); //把管理容器添加到界面中 this.getContentPane().add(jLabel); } } //添加背景图片 JLabel background =new JLabel(new ImageIcon("image/background.png")); background.setBounds(40,40,508,560); //把背景图片添加到界面中 this.getContentPane().add(background); //刷新一下页面 this.getContentPane().repaint(); } private void initJMenuBar() { //创建整个菜单对象 JMenuBar jMenuBar =new JMenuBar(); //创建菜单上面的两个选项的对象(功能 关于我们) JMenu functionJMenu =new JMenu("功能"); JMenu aboutJMenu =new JMenu("关于我们"); //创建更换图片 JMenu changeImage = new JMenu("更换图片"); //把动物,运动添加到更换图片当中 changeImage.add(girl); changeImage.add(animal); changeImage.add(sport); //将每一个条目添加到选项 functionJMenu.add(changeImage); functionJMenu.add(pauseMusicItem); functionJMenu.add(replayItem); functionJMenu.add(reLoginItem); functionJMenu.add(closeItem); aboutJMenu.add(accountItem); //给条目绑定事件 replayItem.addActionListener(this); reLoginItem.addActionListener(this); closeItem.addActionListener(this); accountItem.addActionListener(this); girl.addActionListener(this); animal.addActionListener(this); sport.addActionListener(this); pauseMusicItem.addActionListener(this); //将菜单里面的两个选项添加到菜单 jMenuBar.add(functionJMenu); jMenuBar.add(aboutJMenu); //给整个界面设置菜单 this.setJMenuBar(jMenuBar); } private void initJFrame() { this.setSize(603, 680);//设置宽高 this.setTitle("专属林灿宣的拼图游戏 v1.0");//设置界面标题 this.setAlwaysOnTop(true);//设置界面置顶 this.setLocationRelativeTo(null);//设置界面居中 this.setDefaultCloseOperation(3);//设置关闭模式 this.setLayout(null);//取消内部默认居中方式 this.addKeyListener(this);//给整个界面添加键盘监听事件 File f = new File("music/bgmusic.wav");//不支持MP3,请用格式工厂或其他软件把MP3改为wav,直接改后缀名会报错 try { ais = AudioSystem.getAudioInputStream(f); c = AudioSystem.getClip(); c.open(ais); c.setFramePosition(0); c.start(); } catch (Exception e) { e.printStackTrace(); } //如果GUI是线程运行结束后,需要添加停止播放代码 // c.stop(); } @Override public void keyTyped(KeyEvent e) { // TODO Auto-generated method stub } @Override public void keyPressed(KeyEvent e) { // 按下不松调用方法 int code = e.getKeyCode(); if(code==65) { //把图片全部删除 this.getContentPane().removeAll(); //加载第一张完整的图片 JLabel all=new JLabel(new ImageIcon(path+"all.jpg")); all.setBounds(83,134,420,420); this.getContentPane().add(all); //加载背景图片 //添加背景图片 JLabel background =new JLabel(new ImageIcon("image/background.png")); background.setBounds(40,40,508,560); //把背景图片添加到界面中 this.getContentPane().add(background); //刷新界面 this.getContentPane().repaint(); } } //松开按键时会调用这个方法 @Override public void keyReleased(KeyEvent e) { //判断游戏是否胜利,如果胜利则直接结束方法,不能再执行下面的移动代码 if(victory()) { return; } //对上下左右进行判断 //左:37 上:38 右:39 下:40 int code =e.getKeyCode(); if(code==37) { if(y==3) { return; } //把空白方块右方的数字往左移动 data[x][y]=data[x][y+1]; data[x][y+1]=0; y++; step++; //调用方法按照最新的数字加载图片 initImage(); } else if(code==38) { if(x==3) { //空白方块已经在最下面了 return; } //把空白方块下方的数字往上移动 //x,y表示空白方块 //x+1,y表示空白方块下方的数字 data[x][y]=data[x+1][y]; data[x+1][y]=0; x++; step++; //调用方法按照最新的数字加载图片 initImage(); } else if(code==39) { if(y==0) { return; } //把空白方块左方的数字往右移动 data[x][y]=data[x][y-1]; data[x][y-1]=0; y--; step++; //调用方法按照最新的数字加载图片 initImage(); } else if(code==40) { if(x==0) { return; } //把空白方块上方的数字往下移动 data[x][y]=data[x-1][y]; data[x-1][y]=0; x--; step++; //调用方法按照最新的数字加载图片 initImage(); } else if(code==65) { initImage(); } else if(code==87) { data=new int[][] { {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, {13,14,15,0} }; initImage(); } } //判断是否胜利 public boolean victory() { for(int i=0;i<data.length;i++) { for(int j=0;j<data[i].length;j++) { if(data[i][j]!=win[i][j]) { //只要有一个不一样返回false return false; } } } gameWon = true; return true; } @Override public void actionPerformed(ActionEvent e) { //获取条目对象 Object obj=e.getSource(); if (gameWon) { // 如果游戏已经胜利,点击更换图片菜单项时给出提示 if (obj == girl || obj == animal || obj == sport) { JOptionPane.showMessageDialog(this, "游戏已经胜利,请重新开始游戏!"); return; } } // 判断事件源是哪个菜单项 if (obj == girl) { // 从6组图片中随机选择一组 path = "image/girl/girl" + (new Random().nextInt(6) + 1) + "/"; } else if (obj == animal) { // 从5组动物图片中随机选择一组 path = "image/animal/animal" + (new Random().nextInt(5) + 1) + "/"; } else if (obj == sport) { // 从10组运动图片中随机选择一组 path = "image/sport/sport" + (new Random().nextInt(10) + 1) + "/"; } else if(obj==replayItem) { System.out.println("重新游戏"); gameWon=false; //再次打乱二维数组 initData(); //计步器清零 step=0; //重新加载图片 initImage(); } else if(obj==reLoginItem) { System.out.println("重新登录"); // 暂停音乐播放 if (musicPlaying) { c.stop(); musicPlaying = false; } //关闭当前游戏界面 this.setVisible(false); //打开登录界面 new LoginJFrame(); } else if(obj==closeItem) { System.out.println("关闭游戏"); //直接关闭虚拟机即可 System.exit(0); } else if(obj==accountItem) { System.out.println("联系作者"); //创建一个弹窗对象 JDialog jDialog=new JDialog(); //创建一个管理图片的容器对象 JLabel jLabel=new JLabel(new ImageIcon("image/about.png")); //设置位置和宽高 jLabel.setBounds(0,0,263,258); jDialog.getContentPane().add(jLabel); jDialog.setTitle("联系作者"); //设置弹框大小 jDialog.setSize(344, 344); //让弹框置顶 jDialog.setAlwaysOnTop(true); //让弹框居中 jDialog.setLocationRelativeTo(null); //让弹框不关闭就无法操作下面的界面 jDialog.setModal(true); //让弹框显示出来 jDialog.setVisible(true); } //在actionPerformed方法中处理暂停音乐菜单项的点击事件 else if(obj == pauseMusicItem) { //切换音乐播放状态 musicPlaying = !musicPlaying; if(musicPlaying) { //如果音乐正在播放,恢复播放音乐,并将按钮文本设置为"暂停音乐" c.start(); pauseMusicItem.setText("暂停音乐"); } else { //如果音乐暂停,停止音乐播放,并将按钮文本设置为"播放音乐" c.stop(); pauseMusicItem.setText("播放音乐"); } } //重新加载图片 initImage(); } }
package com.itheima.ui; import com.itheima.domain.User; import com.itheima.util.CodeUtil; import javax.swing.*; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.util.ArrayList; public class LoginJFrame extends JFrame implements MouseListener { static ArrayList<User> allUsers = new ArrayList<>(); static { allUsers.add(new User("admin","123456")); allUsers.add(new User("lcx","210918")); } JButton login = new JButton(); JButton register = new JButton(); JTextField username = new JTextField(); //JTextField password = new JTextField(); JPasswordField password = new JPasswordField(); JTextField code = new JTextField(); //正确的验证码 JLabel rightCode = new JLabel(); public LoginJFrame() { //初始化界面 initJFrame(); //在这个界面中添加内容 initView(); //让当前界面显示出来 this.setVisible(true); } public void initView() { //1. 添加用户名文字 JLabel usernameText = new JLabel(new ImageIcon("image\\login\\用户名.png")); usernameText.setBounds(116, 135, 47, 17); this.getContentPane().add(usernameText); //2.添加用户名输入框 username.setBounds(195, 134, 200, 30); this.getContentPane().add(username); //3.添加密码文字 JLabel passwordText = new JLabel(new ImageIcon("image\\login\\密码.png")); passwordText.setBounds(130, 195, 32, 16); this.getContentPane().add(passwordText); //4.密码输入框 password.setBounds(195, 195, 200, 30); this.getContentPane().add(password); //验证码提示 JLabel codeText = new JLabel(new ImageIcon("image\\login\\验证码.png")); codeText.setBounds(133, 256, 50, 30); this.getContentPane().add(codeText); //验证码的输入框 code.setBounds(195, 256, 100, 30); this.getContentPane().add(code); String codeStr = CodeUtil.getCode(); //设置内容 rightCode.setText(codeStr); //绑定鼠标事件 rightCode.addMouseListener(this); //位置和宽高 rightCode.setBounds(300, 256, 50, 30); //添加到界面 this.getContentPane().add(rightCode); //5.添加登录按钮 login.setBounds(123, 310, 128, 47); login.setIcon(new ImageIcon("image\\login\\登录按钮.png")); //去除按钮的边框 login.setBorderPainted(false); //去除按钮的背景 login.setContentAreaFilled(false); //给登录按钮绑定鼠标事件 login.addMouseListener(this); this.getContentPane().add(login); //6.添加注册按钮 register.setBounds(256, 310, 128, 47); register.setIcon(new ImageIcon("image\\login\\注册按钮.png")); //去除按钮的边框 register.setBorderPainted(false); //去除按钮的背景 register.setContentAreaFilled(false); //给注册按钮绑定鼠标事件 register.addMouseListener(this); this.getContentPane().add(register); //7.添加背景图片 JLabel background = new JLabel(new ImageIcon("image\\login\\background.png")); background.setBounds(0, 0, 470, 390); this.getContentPane().add(background); } public void initJFrame() { this.setSize(488, 430);//设置宽高 this.setTitle("专属林灿宣的拼图游戏 v1.0登录");//设置标题 this.setDefaultCloseOperation(3);//设置关闭模式 this.setLocationRelativeTo(null);//居中 this.setAlwaysOnTop(true);//置顶 this.setLayout(null);//取消内部默认布局 } //点击 @Override public void mouseClicked(MouseEvent e) { if (e.getSource() == login) { System.out.println("点击了登录按钮"); //获取两个文本输入框中的内容 String usernameInput = username.getText(); String passwordInput = password.getText(); //获取用户输入的验证码 String codeInput = code.getText(); //创建一个User对象 User userInfo = new User(usernameInput, passwordInput); System.out.println("用户输入的用户名为" + usernameInput); System.out.println("用户输入的密码为" + passwordInput); if (codeInput.length() == 0) { showJDialog("验证码不能为空"); } else if (usernameInput.length() == 0 || passwordInput.length() == 0) { //校验用户名和密码是否为空 System.out.println("用户名或者密码为空"); //调用showJDialog方法并展示弹框 showJDialog("用户名或者密码为空"); } else if (!codeInput.equalsIgnoreCase(rightCode.getText())) { showJDialog("验证码输入错误"); } else if (contains(userInfo)) { System.out.println("用户名和密码正确可以开始玩游戏了"); //关闭当前登录界面 this.setVisible(false); //打开游戏的主界面 //需要把当前登录的用户名传递给游戏界面 new GameJFrame(); } else { System.out.println("用户名或密码错误"); showJDialog("用户名或密码错误"); } } else if (e.getSource() == register) { System.out.println("点击了注册按钮"); } else if (e.getSource() == rightCode) { System.out.println("更换验证码"); //获取一个新的验证码 String code = CodeUtil.getCode(); rightCode.setText(code); } } public void showJDialog(String content) { //创建一个弹框对象 JDialog jDialog = new JDialog(); //给弹框设置大小 jDialog.setSize(200, 150); //让弹框置顶 jDialog.setAlwaysOnTop(true); //让弹框居中 jDialog.setLocationRelativeTo(null); //弹框不关闭永远无法操作下面的界面 jDialog.setModal(true); //创建Jlabel对象管理文字并添加到弹框当中 JLabel warning = new JLabel(content); warning.setBounds(0, 0, 200, 150); jDialog.getContentPane().add(warning); //让弹框展示出来 jDialog.setVisible(true); } //按下不松 @Override public void mousePressed(MouseEvent e) { if (e.getSource() == login) { login.setIcon(new ImageIcon("image\\login\\登录按下.png")); } else if (e.getSource() == register) { register.setIcon(new ImageIcon("image\\login\\注册按下.png")); } } //松开按钮 @Override public void mouseReleased(MouseEvent e) { if (e.getSource() == login) { login.setIcon(new ImageIcon("image\\login\\登录按钮.png")); } else if (e.getSource() == register) { register.setIcon(new ImageIcon("image\\login\\注册按钮.png")); } } //鼠标划入 @Override public void mouseEntered(MouseEvent e) { } //鼠标划出 @Override public void mouseExited(MouseEvent e) { } //判断用户在集合中是否存在 public boolean contains(User userInput){ for (int i = 0; i < allUsers.size(); i++) { User rightUser = allUsers.get(i); if(userInput.getUsername().equals(rightUser.getUsername()) && userInput.getPassword().equals(rightUser.getPassword())){ //有相同的代表存在,返回true,后面的不需要再比了 return true; } } //循环结束之后还没有找到就表示不存在 return false; } }
package com.itheima.ui; import javax.swing.*; public class RegisterJFrame extends JFrame { //跟注册相关的代码,都写在这个界面中 public RegisterJFrame(){ this.setSize(488,500); //设置界面的标题 this.setTitle("拼图 注册"); //设置界面置顶 this.setAlwaysOnTop(true); //设置界面居中 this.setLocationRelativeTo(null); //设置关闭模式 this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //让显示显示出来,建议写在最后 this.setVisible(true); getContentPane(); } }
package com.itheima.domain; public class User { private String username; private String password; public User() { } public User(String username, String password) { this.username = username; this.password = password; } /** * 获取 * @return username */ public String getUsername() { return username; } /** * 设置 * @param username */ public void setUsername(String username) { this.username = username; } /** * 获取 * @return password */ public String getPassword() { return password; } /** * 设置 * @param password */ public void setPassword(String password) { this.password = password; } }
package com.itheima.util; import java.util.ArrayList; import java.util.Random; public class CodeUtil { public static String getCode(){ //1.创建一个集合 ArrayList<Character> list = new ArrayList<>();//52 索引的范围:0 ~ 51 //2.添加字母 a - z A - Z for (int i = 0; i < 26; i++) { list.add((char)('a' + i));//a - z list.add((char)('A' + i));//A - Z } //3.打印集合 //System.out.println(list); //4.生成4个随机字母 String result = ""; Random r = new Random(); for (int i = 0; i < 4; i++) { //获取随机索引 int randomIndex = r.nextInt(list.size()); char c = list.get(randomIndex); result = result + c; } //System.out.println(result);//长度为4的随机字符串 //5.在后面拼接数字 0~9 int number = r.nextInt(10); //6.把随机数字拼接到result的后面 result = result + number; //System.out.println(result);//ABCD5 //7.把字符串变成字符数组 char[] chars = result.toCharArray();//[A,B,C,D,5] //8.在字符数组中生成一个随机索引 int index = r.nextInt(chars.length); //9.拿着4索引上的数字,跟随机索引上的数字进行交换 char temp = chars[4]; chars[4] = chars[index]; chars[index] = temp; //10.把字符数组再变回字符串 String code = new String(chars); //System.out.println(code); return code; } }