first commit

This commit is contained in:
yunpeng 2024-12-18 20:27:43 +08:00
commit ce783e6706
241 changed files with 29983 additions and 0 deletions

7
.github/dependabot.yml vendored Normal file
View File

@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 20

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
.DS_Store
Thumbs.db
db.json
*.log
node_modules/
public/
.deploy*/
_multiconfig.yml

170
LICENSE Normal file
View File

@ -0,0 +1,170 @@
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors.
Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensors permission is not necessary for any reasonfor example, because of any applicable exception or limitation to copyrightthen that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public.
Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License
By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions.
Section 1 Definitions.
a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License.
c. BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights.
e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike.
h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License.
i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights under this Public License.
k. NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange.
l. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them.
m. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world.
n. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning.
Section 2 Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to:
A. reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and
B. produce, reproduce, and Share Adapted Material for NonCommercial purposes only.
2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions.
3. Term. The term of this Public License is specified in Section 6(a).
4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material.
5. Downstream recipients.
A. Offer from the Licensor Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License.
B. Additional offer from the Licensor Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapters License You apply.
C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material.
6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this Public License.
3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes.
Section 3 License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified form), You must:
A. retain the following if it is supplied by the Licensor with the Licensed Material:
i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of warranties;
v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and
C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information.
3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable.
b. ShareAlike.In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply.
1. The Adapters License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply.
Section 4 Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only;
b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights.
Section 5 Disclaimer of Warranties and Limitation of Liability.
a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You.
b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You.
c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability.
Section 6 Term and Termination.
a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically.
b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
Section 7 Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License.
Section 8 Interpretation.
a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions.
c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor.
d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses.
Creative Commons may be contacted at creativecommons.org.

3
README.md Normal file
View File

@ -0,0 +1,3 @@
# My-Blog-Hexo
hexo 博客

919
_config.butterfly.yml Normal file
View File

@ -0,0 +1,919 @@
# Main menu navigation (導航目錄)
# see https://butterfly.js.org/posts/4aa8abbe/#導航菜單
# --------------------------------------
menu:
主页: / || fas fa-home
文章: /archives/ || fas fa-archive
标签: /tags/ || fas fa-tags
分类: /categories/ || fas fa-folder-open
# List||fas fa-list:
# Music: /music/ || fas fa-music
# Movie: /movies/ || fas fa-video
# Link: /link/ || fas fa-link
# About: /about/ || fas fa-heart
# Code Blocks (代碼相關)
# --------------------------------------
highlight_theme: mac # darker / pale night / light / ocean / mac / mac light / false
highlight_copy: true # copy button
highlight_lang: true # show the code language
highlight_shrink: false # true: shrink the code blocks / false: expand the code blocks | none: expand code blocks and hide the button
highlight_height_limit: false # unit: px
code_word_wrap: false
# copy settings
# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息)
copy:
enable: true
copyright:
enable: false
limit_count: 50
# social settings (社交圖標設置)
# formal:
# icon: link || the description
social:
fab fa-github: https://github.com/AnswerCoder || Github
fas fa-envelope: mailto:zhangyp1015@163.com || Email
# search (搜索)
# see https://butterfly.js.org/posts/ceeb73f/#搜索系統
# --------------------------------------
# Algolia search
algolia_search:
enable: false
hits:
per_page: 6
# Local search
local_search:
enable: false
preload: false
CDN:
# Math (數學)
# --------------------------------------
# About the per_page
# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js)
# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter)
# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true)
# MathJax
mathjax:
enable: false
per_page: false
# KaTeX
katex:
enable: false
per_page: false
hide_scrollbar: true
# Image (圖片設置)
# --------------------------------------
# Favicon網站圖標
favicon: /img/favicon16x16.png
# Avatar (頭像)
avatar:
img: /img/avatar.png
effect: false
# Disable all banner image
disable_top_img: false
# The banner image of home page
index_img: /img/index_img.png
# If the banner of page not setting, it will show the top_img
default_top_img: https://s2.loli.net/2022/08/14/OSlNBJfUAcWYIdF.png
# The banner image of archive page
archive_img:
# If the banner of tag page not setting, it will show the top_img
# note: tag page, not tags page (子標籤頁面的 top_img)
tag_img:
# The banner image of tag page
# format:
# - tag name: xxxxx
tag_per_img:
# If the banner of category page not setting, it will show the top_img
# note: category page, not categories page (子分類頁面的 top_img)
category_img:
# The banner image of category page
# format:
# - category name: xxxxx
category_per_img:
cover:
# display the cover or not (是否顯示文章封面)
index_enable: true
aside_enable: true
archives_enable: true
# the position of cover in home page (封面顯示的位置)
# left/right/both
position: both
# When cover is not set, the default cover is displayed (當沒有設置cover時默認的封面顯示)
default_cover:
- https://s2.loli.net/2022/08/14/4bGjC1YzqQpIKBZ.jpg
- https://s2.loli.net/2022/08/14/7J9RvVH8husy5BE.png
- https://s2.loli.net/2022/08/14/OSlNBJfUAcWYIdF.png
- https://s2.loli.net/2022/08/14/FWfoLexXQO1HDtA.png
# Replace Broken Images (替換無法顯示的圖片)
error_img:
flink: /img/friend_404.gif
post_page: /img/404.jpg
# A simple 404 page
error_404:
enable: true
subtitle: 'Page Not Found'
background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png
post_meta:
page: # Home Page
date_type: both # created or updated or both 主頁文章日期是創建日或者更新日或都顯示
date_format: date # date/relative 顯示日期還是相對日期
categories: true # true or false 主頁是否顯示分類
tags: true # true or false 主頁是否顯示標籤
label: true # true or false 顯示描述性文字
post:
date_type: both # created or updated or both 文章頁日期是創建日或者更新日或都顯示
date_format: date # date/relative 顯示日期還是相對日期
categories: true # true or false 文章頁是否顯示分類
tags: true # true or false 文章頁是否顯示標籤
label: true # true or false 顯示描述性文字
# wordcount (字數統計)
# see https://butterfly.js.org/posts/ceeb73f/#字數統計
wordcount:
enable: true
post_wordcount: true
min2read: true
total_wordcount: true
# Display the article introduction on homepage
# 1: description
# 2: both (if the description exists, it will show description, or show the auto_excerpt)
# 3: auto_excerpt (default)
# false: do not show the article introduction
index_post_content:
method: 3
length: 500 # if you set method to 2 or 3, the length need to config
# anchor
# when you scroll in post, the URL will update according to header id.
anchor: false
# Post
# --------------------------------------
# toc (目錄)
toc:
post: true
page: false
number: true
expand: false
style_simple: false # for post
post_copyright:
enable: true
decode: false
author_href:
license: CC BY-NC-SA 4.0
license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/
# Sponsor/reward
reward:
enable: true
QR_code:
- img: /img/wechatpay.png
link:
text: 微信
- img: /img/alipay.png
link:
text: 支付宝
# Post edit
# Easily browse and edit blog source code online.
post_edit:
enable: false
# url: https://github.com/user-name/repo-name/edit/branch-name/subdirectory-name/
# For example: https://github.com/jerryc127/butterfly.js.org/edit/main/source/
url:
# Related Articles
related_post:
enable: true
limit: 6 # Number of posts displayed
date_type: created # or created or updated 文章日期顯示創建日或者更新日
# figcaption (圖片描述文字)
photofigcaption: false
# post_pagination (分頁)
# value: 1 || 2 || false
# 1: The 'next post' will link to old post
# 2: The 'next post' will link to new post
# false: disable pagination
post_pagination: 1
# Displays outdated notice for a post (文章過期提醒)
noticeOutdate:
enable: false
style: flat # style: simple/flat
limit_day: 500 # When will it be shown
position: top # position: top/bottom
message_prev: It has been
message_next: days since the last update, the content of the article may be outdated.
# Share System (分享功能)
# --------------------------------------
# AddThis
# https://www.addthis.com/
addThis:
enable: false
pubid:
# Share.js
# https://github.com/overtrue/share.js
sharejs:
enable: true
sites: facebook,twitter,wechat,weibo,qq
# AddToAny
# https://www.addtoany.com/
addtoany:
enable: false
item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link
# Comments System
# --------------------------------------
comments:
# Up to two comments system, the first will be shown as default
# Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42
use: # Valine,Disqus
text: true # Display the comment name next to the button
# lazyload: The comment system will be load when comment element enters the browser's viewport.
# If you set it to true, the comment count will be invalid
lazyload: false
count: false # Display comment count in post's top_img
card_post_count: false # Display comment count in Home Page
# disqus
# https://disqus.com/
disqus:
shortname:
apikey: # For newest comments widget
# Alternative Disqus - Render comments with Disqus API
# DisqusJS 評論系統,可以實現在網路審查地區載入 Disqus 評論列表,兼容原版
# https://github.com/SukkaW/DisqusJS
disqusjs:
shortname:
apikey:
option:
# livere (來必力)
# https://www.livere.com/
livere:
uid:
# gitalk
# https://github.com/gitalk/gitalk
gitalk:
client_id:
client_secret:
repo:
owner:
admin:
option:
# valine
# https://valine.js.org
valine:
appId: # leancloud application app id
appKey: # leancloud application app key
avatar: monsterid # gravatar style https://valine.js.org/#/avatar
serverURLs: # This configuration is suitable for domestic custom domain name users, overseas version will be automatically detected (no need to manually fill in)
bg: # valine background
visitor: false
option:
# waline - A simple comment system with backend support fork from Valine
# https://waline.js.org/
waline:
serverURL: # Waline server address url
bg: # waline background
pageview: false
option:
# utterances
# https://utteranc.es/
utterances:
repo:
# Issue Mapping: pathname/url/title/og:title
issue_term: pathname
# Theme: github-light/github-dark/github-dark-orange/icy-dark/dark-blue/photon-dark
light_theme: github-light
dark_theme: photon-dark
# Facebook Comments Plugin
# https://developers.facebook.com/docs/plugins/comments/
facebook_comments:
app_id:
user_id: # optional
pageSize: 10 # The number of comments to show
order_by: social # social/time/reverse_time
lang: en_US # Language en_US/zh_CN/zh_TW and so on
# Twikoo
# https://github.com/imaegoo/twikoo
twikoo:
envId:
region:
visitor: false
option:
# Giscus
# https://giscus.app/
giscus:
repo:
repo_id:
category_id:
theme:
light: light
dark: dark
option:
# Remark42
# https://remark42.com/docs/configuration/frontend/
remark42:
host: # Your Host URL
siteId: # Your Site ID
option:
# Chat Services
# --------------------------------------
# Chat Button [recommend]
# It will create a button in the bottom right corner of website, and hide the origin button
chat_btn: false
# The origin chat button is displayed when scrolling up, and the button is hidden when scrolling down
chat_hide_show: false
# chatra
# https://chatra.io/
chatra:
enable: false
id:
# tidio
# https://www.tidio.com/
tidio:
enable: false
public_key:
# daovoice
# http://daovoice.io/
daovoice:
enable: false
app_id:
# gitter
# https://gitter.im/
gitter:
enable: false
room:
# crisp
# https://crisp.chat/en/
crisp:
enable: false
website_id:
# Footer Settings
# --------------------------------------
footer:
owner:
enable: true
since: 2021
custom_text: <a href="https://beian.miit.gov.cn/#/Integrated/index" style="color:white" target="_blank">豫ICP备2024100875号</a>
copyright: true # Copyright of theme and framework
# Analysis
# --------------------------------------
# Baidu Analytics
# https://tongji.baidu.com/web/welcome/login
baidu_analytics:
# Google Analytics
# https://analytics.google.com/analytics/web/
google_analytics:
# CNZZ Analytics
# https://www.umeng.com/
cnzz_analytics:
# Cloudflare Analytics
# https://www.cloudflare.com/zh-tw/web-analytics/
cloudflare_analytics:
# Microsoft Clarity
# https://clarity.microsoft.com/
microsoft_clarity:
# Advertisement
# --------------------------------------
# Google Adsense (谷歌廣告)
google_adsense:
enable: false
auto_ads: true
js: https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js
client:
enable_page_level_ads: true
# Insert ads manually (手動插入廣告)
# ad:
# index:
# aside:
# post:
# Verification (站長驗證)
# --------------------------------------
site_verification:
# - name: google-site-verification
# content: xxxxxx
# - name: baidu-site-verification
# content: xxxxxxx
# Beautify/Effect (美化/效果)
# --------------------------------------
# Theme color for customize
# Notice: color value must in double quotes like "#000" or may cause error!
# theme_color:
# enable: true
# main: "#49B1F5"
# paginator: "#00c4b6"
# button_hover: "#FF7242"
# text_selection: "#00c4b6"
# link_color: "#99a9bf"
# meta_color: "#858585"
# hr_color: "#A4D8FA"
# code_foreground: "#F47466"
# code_background: "rgba(27, 31, 35, .05)"
# toc_color: "#00c4b6"
# blockquote_padding_color: "#49b1f5"
# blockquote_background_color: "#49b1f5"
# scrollbar_color: "#49b1f5"
# meta_theme_color_light: "ffffff"
# meta_theme_color_dark: "#0d0d0d"
# The top_img settings of home page
# default: top img - full screen, site info - middle (默認top_img全屏site_info在中間)
# The position of site info, eg: 300px/300em/300rem/10% (主頁標題距離頂部距離)
index_site_info_top:
# The height of top_img, eg: 300px/300em/300rem (主頁top_img高度)
index_top_img_height:
# The user interface setting of category and tag page (category和tag頁的UI設置)
# index - same as Homepage UI (index 值代表 UI將與首頁的UI一樣)
# default - same as archives UI 默認跟archives頁面UI一樣
category_ui: # 留空或 index
tag_ui: # 留空或 index
# Website Background (設置網站背景)
# can set it to color or image (可設置圖片 或者 顔色)
# The formal of image: url(http://xxxxxx.com/xxx.jpg)
background:
# Footer Background
footer_bg: false
# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px)
rightside-bottom:
# Enter transitions (開啓網頁進入效果)
enter_transitions: true
# Background effects (背景特效)
# --------------------------------------
# canvas_ribbon (靜止彩帶背景)
# See: https://github.com/hustcc/ribbon.js
canvas_ribbon:
enable: true
size: 150
alpha: 0.6
zIndex: -1
click_to_change: false
mobile: false
# Fluttering Ribbon (動態彩帶)
canvas_fluttering_ribbon:
enable: true
mobile: false
# canvas_nest
# https://github.com/hustcc/canvas-nest.js
canvas_nest:
enable: false
color: '0,0,255' #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.)
opacity: 0.7 # the opacity of line (0~1), default: 0.5.
zIndex: -1 # z-index property of the background, default: -1.
count: 99 # the number of lines, default: 99.
mobile: false
# Typewriter Effect (打字效果)
# https://github.com/disjukr/activate-power-mode
activate_power_mode:
enable: false
colorful: true # open particle animation (冒光特效)
shake: true # open shake (抖動特效)
mobile: false
# Mouse click effects: fireworks (鼠標點擊效果: 煙火特效)
fireworks:
enable: false
zIndex: 9999 # -1 or 9999
mobile: false
# Mouse click effects: Heart symbol (鼠標點擊效果: 愛心)
click_heart:
enable: false
mobile: false
# Mouse click effects: words (鼠標點擊效果: 文字)
ClickShowText:
enable: false
text:
# - I
# - LOVE
# - YOU
fontSize: 15px
random: false
mobile: false
# Default display mode (網站默認的顯示模式)
# light (default) / dark
display_mode: light
# Beautify (美化頁面顯示)
beautify:
enable: false
field: post # site/post
title-prefix-icon: # '\f0c1'
title-prefix-icon-color: # '#F47466'
# Global font settings
# Don't modify the following settings unless you know how they work (非必要不要修改)
font:
global-font-size:
code-font-size:
font-family:
code-font-family:
# Font settings for the site title and site subtitle
# 左上角網站名字 主頁居中網站名字
blog_title_font:
font_link:
font-family:
# The setting of divider icon (水平分隔線圖標設置)
hr_icon:
enable: true
icon: # the unicode value of Font Awesome icon, such as '\3423'
icon-top:
# the subtitle on homepage (主頁subtitle)
subtitle:
enable: true
# Typewriter Effect (打字效果)
effect: true
# loop (循環打字)
loop: true
# source 調用第三方服務
# source: false 關閉調用
# source: 1 調用一言網的一句話(簡體) https://hitokoto.cn/
# source: 2 調用一句網(簡體) http://yijuzhan.com/
# source: 3 調用今日詩詞(簡體) https://www.jinrishici.com/
# subtitle 會先顯示 source , 再顯示 sub 的內容
source: 3
# 如果關閉打字效果subtitle 只會顯示 sub 的第一行文字
sub:
# Loading Animation (加載動畫)
preloader: false
# aside (側邊欄)
# --------------------------------------
aside:
enable: true
hide: false
button: true
mobile: true # display on mobile
position: right # left or right
display:
archive: true
tag: true
category: true
card_author:
enable: true
description:
button:
enable: true
icon: fab fa-github
text: Follow Me
link: https://github.com/AnswerCoder
card_announcement:
enable: true
content: 外面的声音太嘈杂,听自己的心就好
card_recent_post:
enable: true
limit: 5 # if set 0 will show all
sort: date # date or updated
sort_order: # Don't modify the setting unless you know how it works
card_categories:
enable: true
limit: 8 # if set 0 will show all
expand: none # none/true/false
sort_order: # Don't modify the setting unless you know how it works
card_tags:
enable: true
limit: 20 # if set 0 will show all
color: false
sort_order: # Don't modify the setting unless you know how it works
card_archives:
enable: true
type: monthly # yearly or monthly
format: MMMM YYYY # eg: YYYY年MM月
order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
limit: 8 # if set 0 will show all
sort_order: # Don't modify the setting unless you know how it works
card_webinfo:
enable: true
post_count: true
last_push_date: true
sort_order: # Don't modify the setting unless you know how it works
# busuanzi count for PV / UV in site
# 訪問人數
busuanzi:
site_uv: true
site_pv: true
page_pv: true
# Time difference between publish date and now (網頁運行時間)
# Formal: Month/Day/Year Time or Year/Month/Day Time
runtimeshow:
enable: true
publish_date: 2020/04/25
# Aside widget - Newest Comments
newest_comments:
enable: false
sort_order: # Don't modify the setting unless you know how it works
limit: 6
storage: 10 # unit: mins, save data to localStorage
avatar: true
# Bottom right button (右下角按鈕)
# --------------------------------------
# Conversion between Traditional and Simplified Chinese (簡繁轉換)
translate:
enable: true
# The text of a button
default:
# the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese
defaultEncoding: 2
# Time delay
translateDelay: 0
# The text of the button when the language is Simplified Chinese
msgToTraditionalChinese: '繁'
# The text of the button when the language is Traditional Chinese
msgToSimplifiedChinese: '简'
# Read Mode (閲讀模式)
readmode: true
# dark mode
darkmode:
enable: true
# Toggle Button to switch dark/light mode
button: true
# Switch dark/light mode automatically (自動切換 dark mode和 light mode)
# autoChangeMode: 1 Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am
# autoChangeMode: 2 Switch dark mode between 6 pm to 6 am
# autoChangeMode: false
autoChangeMode: false
# Don't modify the following settings unless you know how they work (非必要請不要修改 )
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
# Don't repeat 不要重複
rightside_item_order:
enable: false
hide: # readmode,translate,darkmode,hideAside
show: # toc,chat,comment
# Lightbox (圖片大圖查看模式)
# --------------------------------------
# You can only choose one, or neither (只能選擇一個 或者 兩個都不選)
# medium-zoom
# https://github.com/francoischalifour/medium-zoom
medium_zoom: false
# fancybox
# http://fancyapps.com/fancybox/3/
fancybox: true
# Tag Plugins settings (標籤外掛)
# --------------------------------------
# mermaid
# see https://github.com/mermaid-js/mermaid
mermaid:
enable: false
# built-in themes: default/forest/dark/neutral
theme:
light: default
dark: dark
# Note (Bootstrap Callout)
note:
# Note tag style values:
# - simple bs-callout old alert style. Default.
# - modern bs-callout new (v2-v3) alert style.
# - flat flat callout style with background, like on Mozilla or StackOverflow.
# - disabled disable all CSS styles import of note tag.
style: flat
icons: true
border_radius: 3
# Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6).
# Offset also applied to label tag variables. This option can work with disabled note tag.
light_bg_offset: 0
# other
# --------------------------------------
# Pjax
# It may contain bugs and unstable, give feedback when you find the bugs.
# https://github.com/MoOx/pjax
pjax:
enable: false
exclude:
# - xxxx
# - xxxx
# Inject the css and script (aplayer/meting)
aplayerInject:
enable: false
per_page: true
# Snackbar (Toast Notification 彈窗)
# https://github.com/polonel/SnackBar
# position 彈窗位置
# 可選 top-left / top-center / top-right / bottom-left / bottom-center / bottom-right
snackbar:
enable: false
position: bottom-left
bg_light: '#49b1f5' # The background color of Toast Notification in light mode
bg_dark: '#1f1f1f' # The background color of Toast Notification in dark mode
# https://instant.page/
# prefetch (預加載)
instantpage: false
# https://github.com/vinta/pangu.js
# Insert a space between Chinese character and English character (中英文之間添加空格)
pangu:
enable: false
field: site # site/post
# Lazyload (圖片懶加載)
# https://github.com/verlok/vanilla-lazyload
lazyload:
enable: false
field: site # site/post
placeholder:
blur: false
# PWA
# See https://github.com/JLHwung/hexo-offline
# ---------------
# pwa:
# enable: false
# manifest: /pwa/manifest.json
# apple_touch_icon: /pwa/apple-touch-icon.png
# favicon_32_32: /pwa/32.png
# favicon_16_16: /pwa/16.png
# mask_icon: /pwa/safari-pinned-tab.svg
# Open graph meta tags
# https://developers.facebook.com/docs/sharing/webmasters/
Open_Graph_meta: true
# Add the vendor prefixes to ensure compatibility
css_prefix: true
# Inject
# Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag)
# 插入代码到头部 </head> 之前 和 底部 </body> 之前
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
bottom:
# - <script src="xxxx"></script>
# CDN
# Don't modify the following settings unless you know how they work
# 非必要請不要修改
CDN:
# The CDN provider of internal scripts (主題內部 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# Dev version can only choose. ( dev版的主題只能設置為 local )
internal_provider: local
# The CDN provider of third party scripts (第三方 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# when set it to local, you need to install hexo-butterfly-extjs
third_party_provider: jsdelivr
# Add version number to CDN, true or false
version: false
# Custom format
# For example: https://cdn.staticfile.org/${cdnjs_name}/${version}/${min_cdnjs_file}
custom_format:
option:
# main_css:
# main:
# utils:
# translate:
# local_search:
# algolia_js:
# algolia_search_v4:
# instantsearch_v4:
# pjax:
# gitalk:
# gitalk_css:
# blueimp_md5:
# valine:
# disqusjs:
# disqusjs_css:
# twikoo:
# waline_js:
# waline_css:
# sharejs:
# sharejs_css:
# mathjax:
# katex:
# katex_copytex:
# mermaid:
# canvas_ribbon:
# canvas_fluttering_ribbon:
# canvas_nest:
# lazyload:
# instantpage:
# typed:
# pangu:
# fancybox_css_v4:
# fancybox_v4:
# medium_zoom:
# snackbar_css:
# snackbar:
# activate_power_mode:
# fireworks:
# click_heart:
# ClickShowText:
# fontawesomeV6:
# flickr_justified_gallery_js:
# flickr_justified_gallery_css:
# aplayer_css:
# aplayer_js:
# meting_js:
# prismjs_js:
# prismjs_lineNumber_js:
# prismjs_autoloader:

0
_config.landscape.yml Normal file
View File

107
_config.yml Normal file
View File

@ -0,0 +1,107 @@
# Hexo Configuration
## Docs: https://hexo.io/docs/configuration.html
## Source: https://github.com/hexojs/hexo/
# Site
title: YunPeng's技术博客
subtitle: '随心而动'
description: ''
keywords: Java,感悟,生活
author: yunpeng
language: zh-CN
timezone: 'Asia/Shanghai'
# URL
## Set your site url here. For example, if you use GitHub Page, set url as 'https://username.github.io/project'
url: https://pengspace.top
permalink: :year/:month/:day/:title/
permalink_defaults:
pretty_urls:
trailing_index: true # Set to false to remove trailing 'index.html' from permalinks
trailing_html: true # Set to false to remove trailing '.html' from permalinks
# Directory
source_dir: source
public_dir: public
tag_dir: tags
archive_dir: archives
category_dir: categories
code_dir: downloads/code
i18n_dir: :lang
skip_render:
# Writing
new_post_name: :title.md # File name of new posts
default_layout: post
titlecase: false # Transform title into titlecase
external_link:
enable: true # Open external links in new tab
field: site # Apply to the whole site
exclude: ''
filename_case: 0
render_drafts: false
post_asset_folder: false
relative_link: false
future: true
highlight:
enable: true
line_number: true
auto_detect: false
tab_replace: ''
wrap: true
hljs: false
prismjs:
enable: false
preprocess: true
line_number: true
tab_replace: ''
# Home page setting
# path: Root path for your blogs index page. (default = '')
# per_page: Posts displayed per page. (0 = disable pagination)
# order_by: Posts order. (Order by date descending by default)
index_generator:
path: ''
per_page: 10
order_by: -date
# Category & Tag
default_category: uncategorized
category_map:
tag_map:
# Metadata elements
## https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
meta_generator: true
# Date / Time format
## Hexo uses Moment.js to parse and display date
## You can customize the date format as defined in
## http://momentjs.com/docs/#/displaying/format/
date_format: YYYY-MM-DD
time_format: HH:mm:ss
## updated_option supports 'mtime', 'date', 'empty'
updated_option: 'mtime'
# Pagination
## Set per_page to 0 to disable pagination
per_page: 10
pagination_dir: page
# Include / Exclude file(s)
## include:/exclude: options only apply to the 'source/' folder
include:
exclude:
ignore:
# Extensions
## Plugins: https://hexo.io/plugins/
## Themes: https://hexo.io/themes/
theme: butterfly
# Deployment
## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
repository: git@github.com:AnswerCoder/AnswerCoder.github.io.git
branch: main

4809
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

30
package.json Normal file
View File

@ -0,0 +1,30 @@
{
"name": "hexo-site",
"version": "0.0.0",
"private": true,
"scripts": {
"build": "hexo generate",
"clean": "hexo clean",
"deploy": "hexo deploy",
"server": "hexo server"
},
"hexo": {
"version": "6.2.0"
},
"dependencies": {
"hexo": "^6.2.0",
"hexo-butterfly-tag-plugins-plus": "^1.0.17",
"hexo-deployer-git": "^3.0.0",
"hexo-generator-archive": "^1.0.0",
"hexo-generator-category": "^1.0.0",
"hexo-generator-index": "^2.0.0",
"hexo-generator-tag": "^1.0.0",
"hexo-renderer-ejs": "^2.0.0",
"hexo-renderer-marked": "^5.0.0",
"hexo-renderer-pug": "^3.0.0",
"hexo-renderer-stylus": "^2.1.0",
"hexo-server": "^3.0.0",
"hexo-theme-landscape": "^0.0.3",
"hexo-wordcount": "^6.0.1"
}
}

4
scaffolds/draft.md Normal file
View File

@ -0,0 +1,4 @@
---
title: {{ title }}
tags:
---

4
scaffolds/page.md Normal file
View File

@ -0,0 +1,4 @@
---
title: {{ title }}
date: {{ date }}
---

5
scaffolds/post.md Normal file
View File

@ -0,0 +1,5 @@
---
title: {{ title }}
date: {{ date }}
tags:
---

1
source/CNAME Normal file
View File

@ -0,0 +1 @@
pengspace.top

View File

@ -0,0 +1,302 @@
---
title: Git版本控制工具的使用
date: 2020-12-12 14:03:13
tags:
- Git
- 版本控制
categories:
- 工具使用
---
## 版本控制概述
版本控制是实现开发团队**并行开发、提高开发效率**的基础。其目的在于对软件开发进程中文件或目录的发展过程提供有效的追踪手段,保证在需要时可回到旧的版本,避免文件的丢失、修改的丢失和相互覆盖,通过对版本库的访问控制避免未经授权的访问和修改,达到有效保护企业软件资产和知识产权的目的。
<!--more-->
版本控制的功能在于跟踪记录整个软件的开发过程,包括软件本身和相关文档,以便对不同阶段的软件及相关文档进行表示并进行差别分析,对软件代码进行可撤消的修改,便于汇总不同开发人员所做的修改,辅助协调和管理软件开发团队。
## 常用版本控制工具
### Visual Source Safe(VSS
VSS是美国微软公司的产品目前常用的版本为6.0版。VSS是配置管理的一种很好的入门级的工具。
易学易用是VSS的强项VSS采用标准的windows操作界面只要对微软的产品熟悉就能很快上手。
VSS的配置管理的功能比较基本提供文件的版本跟踪功能对于build和基线的管理VSS的打标签的功能可以提供支持。VSS提供share共享)、branch(分支和合并merge)的功能对于团队的开发进行支持。VSS不提供对流程的管理功能如对变更的流程进行控制。
VSS不能提供对异地团队开发的支持。此外VSS只能在windows平台上运行不能运行在其他操作系统上。
VSS的安全性不高对于VSS的用户可以在文件夹上设置不可读可读可读/写,可完全控制四级权限。但由于VSS的文件夹是要完全共享给用户后用户才能进入所以用户对VSS的文件夹都可以删除。这一点也是VSS的一个比较大的缺点。
**微软已不再对VSS提供技术支持。**
### Concurrent Version System(CVS
CVS是开发源代码的配置管理工具其源代码和安装文件都可以免费下载。
CVS是源于unix的版本控制工具CVS的服务器管理需要进行各种命令行操作。目前CVS的客户端有winCVS的图形化界面服务器端也有CVSNT的版本易用性正在提高。
CVS的功能除具备VSS的功能外还具有
它的客户机/服务器存取方法使得开发者可以从任何因特网的接入点存取最新的代码;它的无限制的版本管理检出(checkout)的模式避免了通常的 因为排它检出模式而引起的人工冲突它的客户端工具可以在绝大多数的平台上使用。同样CVS不提供对变更流程的自动管理功能。
一般来说CVS的权限设置单一通常只能通过CVSROOT/passwdCVSROOT/readersCVSROOT/writers文件同时还要设置CVS REPOS的物理目录权限来完成权限设置无法完成复杂的权限控制但是CVS通过CVS ROOT目录下的脚本提供了相应功能扩充的接口不但可以完成精细的权限控制还能完成更加个性化的功能。
CVS是开发源码软件没有生产厂家为其提供技术的支持。如发现问题通常只能靠自己查找网上的资料进行解决。
### SVN
SVN全名Subversion即版本控制系统。
SVN与CVS一样是一个跨平台的软件支持大多数常见的操作系统。作为一个开源的版本控制系统Subversion 管理着随时间改变的数据。 这些数据放置在一个中央资料档案库中。 这个档案库很像一个普通的文件服务器, 不过它会记住每一次文件的变动。 这样你就可以把档案恢复到旧的版本, 或是浏览文件的变动历史。Subversion 是一个通用的系统, 可用来管理任何类型的文件, 其中包括了程序源码。
### Git
Git是一个开源的**分布式**版本控制系统,用以有效、高速的处理从很小到非常大的项目版本管理。
Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。
Torvalds 开始着手开发 Git 是为了作为一种过渡方案来替代 BitKeeper后者之前一直是 Linux 内核开发人员在全球使用的主要源代码工具。开放源码社区中的有些人觉得 BitKeeper 的许可证并不适合开放源码社区的工作,因此 Torvalds 决定着手研究许可证更为灵活的版本控制系统。尽管最初 Git 的开发是为了辅助 Linux 内核开发的过程,但是我们已经发现在很多其他自由软件项目中也使用了 Git。
### Git和SVN的区别
* Git 是分布式的SVN 不是:
这是 Git 和其它非分布式的版本控制系统,例如 SVNCVS 等,最核心的区别。
* Git 把内容按元数据方式存储,而 SVN 是按文件:
所有的资源控制系统都是把文件的元信息隐藏在一个类似 .svn、.git 等的文件夹里。
* Git 分支和 SVN 的分支不同:
分支在 SVN 中一点都不特别,其实它就是版本库中的另外一个目录。**Git 分支是指针指向某次提交,而 SVN 分支是拷贝的目录**。这个特性使 Git 的分支切换非常迅速,且创建成本非常低。
**Git 有本地分支SVN 无本地分支**。在实际开发过程中,经常会遇到有些代码没写完,但是需紧急处理其他问题,若我们使用 Git便可以创建本地分支存储没写完的代码待问题处理完后再回到本地分支继续完成代码。
* Git 没有一个全局的版本号,而 SVN 有:
目前为止这是跟 SVN相比Git 缺少的最大的一个特征。
* Git 的内容完整性要优于 SVN
Git 的内容存储使用的是 SHA-1 哈希算法。这能确保代码内容的完整性,确保在遇到磁盘故障和网
络问题时降低对版本库的破坏。
![](https://i.loli.net/2020/11/27/7rwU4cupNyPqlbo.png)
## Git的使用
### 安装
可以进入官网[https://git-scm.com/](https://git-scm.com/),选择适合自己电脑的版本下载并安装。
![](https://i.loli.net/2020/11/27/pRV15kXo3ydm8Wa.png)
安装时一路next即可。需要注意的点有
![选择Bash和GUI](https://i.loli.net/2020/11/27/M3mkjfQh1l8KICc.png)
仅供参考。
安装完成后在桌面或任意文件夹单击鼠标右键,出现*Git Bash Here*/ *Git GUI Here*则说明安装成功
![](https://i.loli.net/2020/11/27/LYXTGHfc9DWu2gd.png)
或者在cmd终端输入`git --version`,出现版本说明安装成功
![image-20201127135807275](https://i.loli.net/2020/11/27/8vGaIdZS5rLNeCT.png)
### Git工作区域
git的工作区域分为3个区域工作区、暂存区和仓库区。3个区的功能分别为
1. 工作区:用来对代码进行修改(也就是我们的工作文件夹内部的文件本身,或者说是我们本地的文件夹)
2. 暂存区:暂时存放准备放入仓库区的代码
3. 仓库区:存放各个版本的代码
三个区之间的联系和文件操作如下图所示
![](https://i.loli.net/2020/11/27/sqL4HgNiS3FDbBz.png)
### Git初始化仓库和常用指令
初始化仓库的步骤如下:
1. 在我们想要进行版本控制的文件夹中右键打开git bash
2. 在文件夹内初始化git(创建git仓库)
`git init` (会生成一个.git的隐藏文件
常用指令:
* **add 添加文件**
格式:`git add 文件名`
作用:将工作区的文件提交(此时文件**提交至暂存区**
> 注:如果文件名参数为`*`,表示提交当前目录下的所有文件。目录路径可以用`/`分隔开。
* **rm 删除文件**
格式:`git rm 文件名`
作用:删除文件(工作区/库一起删除)
> 注:如果想要删除文件夹,则添加参数`-r` `git rm -r 文件夹`
>
> 当我们需要删除暂存区或分支上的文件, 但本地又需要使用,只是不希望这个文件被版本控制, 可以使用下面迷命令只删除暂存区和版本库中的文件,保留工作区文件:
>
> `git rm -r --cached 文件夹名称`
* **status 查看当前状态**
格式:`git status`
作用:查看暂存区状态(有多少条指令待执行)
* **commit 提交**
格式:`git commit -m "提交描述"`
作用:执行暂存区的指令。提交描述表示这次提交的描述信息。
## Git远程服务器
git常见的远程服务器有
* [GitHub](https://github.com/)
* [GitLab](https://gitlab.com/users/sign_in)
* [Gitee码云](https://gitee.com/)
其中GitHub和GitLab都是国外服务商在国内访问速度可能会受到限制。Gitee是国内的代码托管与开发协作平台在国内的访问速度相比GitHub和GitLab要快很多。
> **==GitHub==**
>
> 通过git管理github托管项目代码。
>
> > GitHub是一个面向开源及私有软件项目的托管平台因为只支持git 作为唯一的版本库格式进行托管故名GitHub。
> >
> > GitHub于2008年4月10日正式上线除了git代码仓库托管及基本的Web管理界面以外还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。目前,其注册
> > 用户已经超过350万托管版本数量也是非常之多其中不乏知名开源项目 Rubyon Rails、jQuery、python等。
>
> **==GitLab==**
>
> > GitHub 和 GitLab 都是基于 web 的 Git 仓库,使用起来二者差不多,它们都提供了分享开源项目的平台,为开发团队提供了存储、分享、发布和合作开发项目的中心化云存储的场所。
> >
> > GitHub 作为开源代码库,拥有超过 900万的开发者用户目前仍然是最火的开源项目托管平台GitHub 同时提供公共仓库和私有仓库,但如果使用私有仓库,是需要付费的。
> >
> > GitLab 解决了这个问题,你可以在上面创建**私人的免费仓库**。 GitLab 让开发团队对他们的代码仓库拥有更多的控制相比较GitHub , 它有不少特色:
> >
> > (1) 允许免费设置仓库权限;
> >
> > (2) 允许用户选择分享一个 project 的部分代码;
> >
> > (3) 允许用户设置 project 的获取权限,进一步提升安全性;
> >
> > (4) 可以设置获取到团队整体的改进进度;
> >
> > (5) 通过innersourcing 让不在权限范围内的人访问不到该资源;
> >
> > 所以从代码的私有性上来看GitLab是一个更好的选择。但是对于开源项目而言GitHub 依然是代码托管的首选。
>
> **==Gitee(码云)==**
>
> > 码云Gitee是 OSCHINA 推出的代码托管协作开发平台,支持 Git 和 SVN,提供免费的私有仓库托
> > 管。2016 年推出企业版,提供企业级代码托管服务,成为开发领域领先的 SaaS 服务提供商。
> >
> > Gitee除了访问速度更快以外Gitee 还提供了**免费的私有仓库**供个人开发者使用。同时Gitee 也有着国内数一数二的开源生态这里有非常多的优秀开源项目和开发者你可以在这里和他们无障碍地沟通交流不管是找开源项目还是分享自己的开源项目Gitee 都是极佳的选择。
> >
> > 作为国内代码托管平台的佼佼者,目前已经有超过 500 万名开发者在 Gitee 上托管了 1000 余万个代码仓库,而其提供了研发管理、代码托管、文档管理服务的企业版的服务客户也超过了 10 万家。
下面针对Gitee说一下Git远程服务器的使用
### Gitee的使用
#### Gitee的一些基本概念
1. 仓库(**Repository**
仓库即你的项目你想在github上开源一个项目那就必须要新建一个repository,如果你开源的项目
多,那你拥有的仓库也就很多
2. 收藏(**star**
仓库主页的star按钮意思是收藏项目的人数。
3. 复制克隆项目(**fork**
在原项目的基础上新增代码和结构也可以理解成拿别人的代码进行二次加工。Fork后会在自己账号下生成自己的相同仓库
4. 发起请求(**pull request**,简称**PR**
这个是基于fork的当其他人改进完代码后想将这个项目合并到原项目则这个时候会给你发起一个pull request。如果接受了请求这个时候就可以拥有改进的项目了。
5. 关注(**watch**
即观察,可以随时看到被关注项目的更新
6. 事务卡片(**Issue**
发现代码有bug,但是目前还没成型需要讨论时使用。当别人发现你的问题时会提个lssue。
7. Gitee主页
账号创建完后点击导航栏gitee图标即可进入主页。左侧显示功能列表右侧显示仓库动态。
8. 仓库主页
仓库主页主要显示项目的信息,如:代码版本收藏关注fork等
#### 创建仓库
注册登录后就可以创建仓库了一个本地git库对应一个远程开源项目。
![](https://i.loli.net/2020/11/27/PRDvlxUNTSz5oeK.png)
![](https://i.loli.net/2020/11/27/9vxr7ZfkeudGJtS.png)
#### 本地Git操作远程仓库
本地配置gitee的一些配置教程可以参考[https://gitee.com/help/articles/4107](https://gitee.com/help/articles/4107)。
设置登录的账户信息: 用户名和邮箱地址是本地git客户端的一个变量每次commit都会用用户名和邮箱纪录。
一些配置的方法如下:
```bash
# 设置用户名:
git config --global user.name '用户名'
#设置邮箱:
git config --global user.email '邮箱'
```
> 查看git的配置:
>
> ```bash
> git config --list
> ```
git管理远程仓库的常用指令
* `git clone 仓库地址`:将远程仓库的项目复制到本地
* `git push`将本地仓库提交到远程注意先提交到缓存区再提交到仓库最后提交远程也就是在给commit 之后再 push
* `git pull`:更新本地仓库至最新改动
#### IDEA配置Git+Gitee
1. IDEA配置Git客户端:
File - Settings - Version Control - Git
配置Path to Git Executable就是git的所在路径
![image-20201127151002861](https://i.loli.net/2020/11/27/9y3dg8eNqY7moTj.png)
2. 下载gitee插件GitHub等同理
File - Settings - Plugins
搜索Gitee然后点击Install。安装完毕后重启IDEA。
![](https://i.loli.net/2020/11/27/DnQpXw5NEAZL4M9.png)
3. 添加信息
File - Setting - Version Control - Gitee![](https://i.loli.net/2020/11/27/OCtmyaiE2xg4Qs8.png)
填写login和passwordlogin填写邮箱。
4. 上传和下载
上传VCS - Import Into Version Control - Share Project To Gitee
下载新建项目时Get from Version Control
![](https://i.loli.net/2020/11/27/M91ldHjWUvSN2nk.png)

View File

@ -0,0 +1,310 @@
---
title: JavaWeb环境搭建(Tomcat)
date: 2020-12-12 13:47:17
tags:
- JavaWeb
- tomcat
categories:
- JavaWeb
---
## HTTP 协议
### 简介
超文本传输协议(`HyperText Transfer Protocol`缩写HTTP是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
<!--more-->
HTTP的发展是由蒂姆·伯纳斯-李于1989年在欧洲核子研究组织CERN所发起。HTTP的标准制定由万维网协会World Wide Web ConsortiumW3C和互联网工程任务组Internet Engineering Task ForceIETF进行协
最终发布了一系列的RFC其中最著名的是1999年6月公布的 RFC 2616定义了HTTP协议中现今广泛使用的一个版本——HTTP 1.1。
![五层协议](https://i.loli.net/2020/11/18/hfFxIbpreuc3siy.png)
HTTP协议是基于TCP/IP协议之上的应用层协议。
HTTP是一种不保存状态即无状态stateless)协议。HTTP协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别协议对于发送过的请求或响应都不做持久化处理。
### 请求/响应的步骤
1. **客户端连接到Web服务器**
一个HTTP客户端通常是浏览器与Web服务器的HTTP端口默认为80建立一个TCP套接字连接。
2. **发送HTTP请求**
通过TCP套接字客户端向Web服务器发送一个文本的请求报文一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
3. **服务器接受请求并返回HTTP响应**
Web服务器解析请求定位请求资源。服务器将资源复本写到TCP套接字由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。
4. **释放TCP连接**
在HTTP/1.0中默认使用**短连接**。也就是说客户端和服务器每进行一次HTTP操作就建立一次连接任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源如JavaScript文件、图像文件、CSS文件等每遇到这样一个Web资源浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起默认使用长连接用以保持连接特性。使用长连接的HTTP协议会在响应头加入这行代码`Connection:keep-alive`
在使用**长连接**的情况下当一个网页打开完成后客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭客户端再次访问这个服务器时会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接它有一个保持时间可以在不同的服务器软件如Apache中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
> HTTP协议的长连接和短连接实质上是TCP协议的长连接和短连接。
5. **客户端浏览器解析HTML内容**
客户端浏览器首先解析状态行查看表明请求是否成功的状态代码。然后解析每一个响应头响应头告知以下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML根据HTML的语法对其进行格式化并在浏览器窗口中显示。
> 例如在浏览器地址栏键入URL按下回车之后会经历以下流程
>
> 1. 浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
> 2. 解析出 IP 地址后,根据该 IP 地址和默认端口 80和服务器建立TCP连接;
> 3. 浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为 TCP 三次握手的第三个报文的数据发送给服务器;
> 4. 服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
> 5. 浏览器将该 html 文本并显示内容;
### HTTP请求方法
HTTP/1.1协议中共定义了八种方法(动作)来以不同方式操作指定的资源:
* **<font color=red>GET</font>**
向指定的资源发出「显式」请求。使用GET方法应该只用在读取数据而不应当被用于产生「副作用」的操作中例如在Web Application中。其中一个原因是GET可能会被网络爬虫等随意访问。
* **HEAD**
与GET方法一样都是向服务器发出指定资源的请求。只不过服务器将不传回资源的本文部分。它的好处在于使用这个方法可以在不必传输全部内容的情况下就可以获取其中「关于该资源的信息」(元信息或称元数据)。
* **<font color=red>POST</font>**
向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会创建新的资源或修改现有资源,或二者皆有。
* **<font color=red>PUT</font>**
向指定资源位置上传其最新内容。
* **<font color=red>DELETE</font>**
请求服务器删除Request-URI所标识的资源。
* **TRACE**
回显服务器收到的请求,主要用于测试或诊断。
* **OPTIONS**
这个方法可使服务器传回该资源所支持的所有HTTP请求方法。用`*`来代替资源名称向Web服务器发送OPTIONS请求可以测试服务器功能是否正常运作。
### C/S与B/S
`C/S`又称Client/Server或客户/服务器模式。服务器通常采用高性能的PC、工作站或小型机客户端需要安装专用的客户端软件。如QQ微信等软件
`B/S`是Brower/Server的缩写客户机上只要安装一个浏览器Browser。Browser/Server是建立在广域网的基础上的。
**C/S和B/S结构各自的优、缺点**
| | 优点 | 缺点 |
| ---- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| C/S | 1. 交互性强客户端有着一套完整的应用程序相对B/S有着更加强大的功能还可以实现子程序之间的切换 <br>2. 安全性强,只适用于局域网,相对来说其安全比较好; <br>3. 处理信息能力强C/S的通信量相对B/S是少了很多的<br>4. 速度较快,更加利于处理大量数据。 | 1. 只适用于局域网; <br>2. 客户端要安装专用的客户端软件; <br>3. 每当系统升级时,每一台客户机需要重新安装; <br>4. 操作系统可能会有限制。 |
| B/S | 1. 客户端零维护;<br>2. 系统扩展容易; <br>3. 在电脑可上网的前提下,可以在任何操作系统上使用并且不需要安装专门的软件 。 | 1. 相对C/S来说交互能力差不能够在子程序间自由切换<br>2. 安全性较差B/S其安全性只能靠数据库服务器上管理密码的数据库来保证<br>3. 逻辑结构比C/S多一层处理速度较慢 |
### Web服务器的分类
Web服务器是运行及发布Web应用的容器只有将开发的Web项目放置到该容器中才能使网络中的所有用户通过浏览器进行访问。开发Java Web应用所采用的服务器主要是与JSP/Servlet兼容的Web服务器比较常用的有
Tomcat、Resin、JBoss、WebSphere 和 WebLogic 等。
* **Tomcat 服务器**
目前最为流行的Tomcat服务器是Apache-Jarkarta开源项目中的一个子项目是一个小型、轻量级的支持JSP和Servlet 技术的Web服务器也是初学者学习开发JSP应用的首选。
* **Resin 服务器**
Resin是Caucho公司的产品是一个非常流行的支持Servlet和JSP的服务器速度非常快。Resin本身包含了一个支持HTML的Web服务器这使它不仅可以显示动态内容而且显示静态内容的能力也毫不逊色因此许多网站都是使用Resin服务器构建
* **JBoss服务器**
JBoss是一个种遵从JavaEE规范的、开放源代码的、纯Java的EJB服务器对于J2EE有很好的支持。JBoss采用JML API实现软件模块的集成与管理其核心服务又是提供EJB服务器不包含Servlet和JSP的Web容器不过它可以和Tomcat完美结合
* **WebSphere 服务器**
WebSphere是IBM公司的产品可进一步细分为 WebSphere Performance Pack、Cache Manager 和WebSphere Application Server等系列其中WebSphere Application Server 是基于Java 的应用环境,可以运行于 Sun Solaris、Windows NT 等多种操作系统平台用于建立、部署和管理Internet和Intranet Web应用程序。
* **WebLogic 服务器**
WebLogic 是BEA公司的产品现在已经被Oracle收购可进一步细分为 WebLogic Server、WebLogic Enterprise 和 WebLogic Portal 等系列,其中 WebLogic Server 的功能特别强大。WebLogic 支持企业级的、多层次的和完全分布式的Web应用并且服务器的配置简单、界面友好。对于那些正在寻求能够提供Java平台所拥有的一切应用服务器的用户来说WebLogic是一个十分理想的选择
### Tomcat
> tomcat的使用是基于java的所以要保证我们的电脑已经有了java环境。
#### 安装与配置
1. 去官网下载对应版本的Tomcat
官网地址:[https://tomcat.apache.org/](https://tomcat.apache.org/)
![](https://i.loli.net/2020/11/19/LFWV4eRbshPjHT2.png)
2. 解压或安装到一个没有特殊符号的目录中最好不要包含中文路径我这里下载的是zip包解压即可
![](https://i.loli.net/2020/11/19/ZU4FcjzMwsgvBmI.png)
3. 配置环境变量
右键点击此电脑,打开属性,找到高级系统设置->环境变量->系统变量
(1) 新建一个变量CATALINA_HOME值为tomcat安装的路径结尾不要分号
![](https://i.loli.net/2020/11/19/R48ChW7Ke62lBJX.png)
(2) 配置Path变量找到系统变量中的Path变量点击编辑新建一个值为`%CATALINA_HOME%\bin`
![image-20201119154624242](https://i.loli.net/2020/11/19/NLkDgfbMwEXK37z.png)
(3) 配置ClassPath变量找到系统变量中的ClassPath变量(没有就新建一个),值为`%CATALINA_HOME%\servlet-api.jar`
![](https://i.loli.net/2020/11/19/Sr8WiypNugD5bhv.png)
4. 将tomcat9安装到windows服务中**(可做可不做)**
打开cmd命令行输入`service install Tomcat9`
![](https://i.loli.net/2020/11/19/9lVhyzNZaGBHLgi.png)
如果报以下错误:
```bash
The file Tomcat9.exe was not found...
Either the CATALINA_HOME environment variable is not defined correctly or ....省略
```
找到环境变量Path编辑文本去除`%CATALINA_HOME%\bin`后面的分号,安装成功后再加上分号。
> **注意:** 第四步将tomcat9安装到windows服务中可做可不做做这步的目的就是使解压后bin文件夹下的tomcat9.exe和tomcat9w.exe也可以运行使得绿色解压版和exe安装版安装tomcat的功能一样完整。
至此配置工作完成打开bin文件夹双击startup.bat(或tomcat9.exe)启动tomcat服务因为配置了环境变量也可以直接在cmd中输入startup.bat(或tomcat9.exe)它会自动打开一个控制台界面。不要关闭控制台界面打开浏览器输入http://localhost:8080出现Tomcat的网页证明安装并配置成功最后关闭控制台关闭控制台即关闭Tomcat服务。
![](https://i.loli.net/2020/11/19/gJXnYDIEoVxWpU1.png)
#### tomcat内目录的含义
![](https://i.loli.net/2020/11/19/6BX4YlwgFntjVka.png)
1. **bin**该目录下存放的是二进制可执行文件有两个exe文件tomcat9.exe、tomcat9w.exe前者是在控制台下启动Tomcat后者是弹出GUI窗口启动Tomcat有有两个bat文件startup.bat和shutdown.batstartup.bat用来启动Tomcatshutdown.bat用来停止Tomcat
2. **conf**:这是一个**非常非常重要**的目录,这个目录下有四个最为重要的文件:
* server.xml配置整个服务器信息。例如修改端口号添加虚拟主机等
* tomcat-users.xml存储tomcat用户的文件这里保存的是tomcat的用户名及密码以及用户的角色信息。可以按着该文件中的注释信息添加tomcat用户然后就可以在Tomcat主页中进入Tomcat Manager页面了
* web.xml部署描述符文件这个文件中注册了很多MIME类型即文档类型。这些MIME类型是客户端与服务器之间说明文档类型的如用户请求一个html网页那么服务器还会告诉客户端浏览器响应的文档是text/html类型的这就是一个MIME类型。客户端浏览器通过这个MIME类型就知道如何处理它了但如果服务器响应的是一个exe文件那么浏览器就不可能显示它而是应该弹出下载窗口才对。
MIME就是用来说明文档的内容是什么类型的
* context.xml对所有应用的统一配置通常我们不会去修改它。
3. **lib**Tomcat的类库里面是一大堆jar文件。如果需要添加Tomcat依赖的jar文件可以把它放到这个目录中当然也可以把应用依赖的jar文件放到这个目录中这个目录中的jar所有项目都可以共享之但这样你的应用放到其他Tomcat下时就不能再共享这个目录下的Jar包了所以建议只把Tomcat需要的Jar包放到这个目录下
4. **logs**这个目录中都是日志文件记录了Tomcat启动和关闭的信息如果启动Tomcat时有错误那么异常也会记录在日志文件中。
5. **temp**存放Tomcat的临时文件这个目录下的东西可以在停止Tomcat后删除
6. **webapps**存放web项目的目录其中每个文件夹都是一个项目如果这个目录下已经存在了目录那么都是tomcat自带的项目。其中ROOT是一个特殊的项目在地址栏中没有给出项目目录时对应的就是ROOT项目。
如:http://localhost:8080/examples进入示例项目。其中examples就是项目名即文件夹的名字
7. **work**运行时生成的文件最终运行的文件都在这里。通过webapps中的项目生成的可以把这个目录下的内容删除再次运行时会生再次生成work目录。当客户端用户访问一个JSP文件时Tomcat会通过JSP生成Java文件然后再编译Java文件生成class文件生成的java和class文件都会存放到这个目录下。
8. LICENSE许可证。
9. NOTICE说明文件。
> 通过url访问服务器:
>
> url:`http://服务器的ip地址:端口号/项目名/被访问的页面`
>
> 示例:http://localhost:8080/test
>
> 注: (1)启动tomcat后tomcat会加载部署在服务器端的所有项目
>
> (2) 浏览器访问的页面是服务器端的页面,基本上服务器的项目和工作空间的项目要保持一致
#### IntelliJ IDEA配置Tomcat
1. 点击Run---Edit Configurations...
![image-20201119140937936](https://i.loli.net/2020/11/19/1Cn2XGP9qJDSbps.png)
2. 点击左侧`+`号找到Tomcat Server---Local
![image-20201119141510118](https://i.loli.net/2020/11/19/jNtDmAagkslSCHQ.png)
3. 在Tomcat Server -> local-> Server -> Application server项目下点击 Configuration ,找到本地 Tomcat 服务器,再点击 OK按钮。
![](https://i.loli.net/2020/11/19/lzRZYnPJ7isoBuD.png)
至此IntelliJ IDEA配置Tomcat完成。
#### 创建JavaWeb项目
1. 点击左上角的File-->New-->Project选择Java Enterprise在Application Sever中找到自己的Tomcat同时勾中Web Application 和 Create web.xml点击next输入项目名称和路径点击finish即可。
![](https://i.loli.net/2020/11/19/ObvQ3RBUK5f4ptT.png)
2. 创建好之后文件结构如下:
![](https://i.loli.net/2020/11/19/phctYUqvHFOK87P.png)
3. 在WEB-INF文件夹下创建classes和lib文件夹名字不可改
* classes用来存放java文件编译后的字节码文件
* lib用来存放项目所需的jar依赖包
4. 配置jar包和classes包
(1) 在File中找到Project Structure点击Modules选择Paths选中Use module compile output path把路径改成刚刚创建的classes文件夹点击apply
![](https://i.loli.net/2020/11/19/2IEsGwbJ7cfHZWo.png)
如果classes文件夹没有变颜色就右键点击classes文件夹选择Mark Diectory as —>Exclued
![image-20201119152102261](https://i.loli.net/2020/11/19/qVIJ6zkiA8pamwF.png)
(2) 选择Dependencies点右边的`+`号 选择1 JARs or directories选择刚创建的lib文件夹点ok选择Jar Directory点击ok。
![image-20201119150048728](https://i.loli.net/2020/11/19/oRJ6tG2417QYXyB.png)
5. 部署项目:将本地项目安装到服务器中
(1) idea主界面顶部菜单栏点击Run 选择Edit Configurations可以配置一些信息
![image-20201119151516787](https://i.loli.net/2020/11/19/YBGwXlTr8RtyEgC.png)
(2) 运行
![image-20201119151559538](https://i.loli.net/2020/11/19/yYjEz69HNfcUKVs.png)
![](https://i.loli.net/2020/11/19/lWfI9AZjS8RKsuB.png)
运行成功
#### tomcat常用操作
##### 修改端口号
修改配置文件:/conf/server.xml 的port
```xml
<Connector port="8888" protocol="HTTP/1.1" connectionTimeout="20000"redirectPort="8443" />
```
如果将端口号改成80则访问项目时的请求路径就可以省略端口号。
##### 管理项目
给tomcat增加管理员信息配置conf/tomcat-users.xml
在tomcat-users.xml文件中添加下面代码
```xml
<role rolename="manager-gui"/>
<user username="tomcat" password="tomcat" roles="manager-gui"/>
```
![](https://i.loli.net/2020/11/19/T8Jt6WEqbKahwuR.png)
点击Manager App会弹出下面这个框我们输入tomcat-users.xml文件中添加的管理员账户密码就可以看到当前tomcat服务器中的所有web应用。
![](https://i.loli.net/2020/11/19/O9NwRqvClfs4kHu.png)
![](https://i.loli.net/2020/11/19/amVHeL2jqshwYtA.png)
注意:tomcat启动的时候会加载webapps下的所有项目

View File

@ -0,0 +1,880 @@
---
title: Java多线程
date: 2020-10-24 16:23:00
tags:
- Java
- 多线程
categories:
- Java基础
---
## 多线程概述
==多线程:栈空间独立,堆内存共享==
多线程是实现并发机制的一种有效手段。进程和线程一样,都是实现并发的一个基本单位。线程是比进程更小的执行单位,线程是在进程的基础上进行的进一步划分。所谓多线程是指一个进程在执行过程中可以产生多个线程,这些线程可以同时存在、同时运行,一个进程可能包含了多个同时执行的线程。
<!-- more -->
### 进程与线程
* **进程**
* 正在运行的应用程序:是指一个内存中运行的应用程序,**每个进程都有一个独立的内存空间**,即每个进程都有着自己的堆、栈等且是互不共享的。
* **线程**
* 进程中的一个**执行路径**(一段程序从执行到结束的整个过程),共享一个内存空间,线程之间可以自由切换,并发执行,<font color=red>一个进程最少有一个线程</font>
* 线程实际上是在进程的基础上进一步划分的,一个进程执行后,里面的若干执行路径又可以划分为若干个线程
### 线程调度
1. **分时调度**
* 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
2. **抢占式调度**
* 优先让优先级高的线程使用 CPU如果线程的优先级相同那么会随机选择一个(线程随机性)**Java使用的为抢占式调度**。
* CPU使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核心而言某个时刻只能执行一个线程而 CPU的在多个线程间切换速度相对我们的感觉很快看上去就是在同一时刻运行。 其实多线程程序并不能提高程序的运行速度但能够提高程序运行效率让CPU的使用率更高。
### 同步与异步&并发与并行
> **同步**:排队执行,效率低但安全
>
> **异步**:同时执行,效率高但数据不安全
> **并发**:指两个或多个事件在<font color=red>同一个时间段内</font>发生。
>
> **并行**:指两个或多个事件在<font color=red>同一时刻</font>发生(同时发生)。
## 多线程的实现方式
### 继承Thread类
步骤:
1. 创建一个自定义类并继承Thread类
2. 重写run()方法创建新的执行任务通过thread对象的start()方法启动任务一般不直接调用run()方法)
3. 创建自定义类对象实例调用start(),让线程执行
代码如下:
```java
//MyThread.java
public class MyThread extends Thread{
@Override
public void run() { //run()方法就是线程要执行的任务的方法
for (int i = 0; i < 10; i++) {
System.out.println("MyThread" + i);
}
}
}
//ThreadTest.java
public class ThreadTest {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.start(); //启动线程任务
for (int i = 0; i < 5; i++) {
System.out.println("MainThread" + i);
}
}
}
```
运行结果:
可以看到顺序并不统一,两个线程在交替执行而且各自所占的时间不完全相同,这是线程在抢时间片,谁先抢到谁就执行。
![image-20201020195837780](https://i.loli.net/2020/10/20/t4hNj7XJWOHBuvr.png)
> **时序图:**
>
> ![image-20201020202118525](https://i.loli.net/2020/10/20/ZeTkrMvRzSK8t3F.png)
>
> 运行过程中子线程任务中调用的方法都在子线程中运行
> 在上述代码中。如果Thread对象只需要调用1次也可以通过使用匿名内部类的方式进行简化
>
> ```java
> public class ThreadTest {
> public static void main(String[] args) {
> new Thread(){
> public void run() {
> for (int i = 0; i < 5; i++) {
> System.out.println("MyRunnable" + i);
> }
> }
> }.start();
> for (int i = 0; i < 5; i++) {
> System.out.println("MainThread" + i);
> }
> }
> }
> ```
### 实现Runnable接口
Runnable接口代码
```java
public interface Runnable {
public abstract void run();
}
```
步骤:
1. 创建一个自定义类实现Runnable接口并实现其抽象方法run(),编写线程要执行的任务
2. 创建自定义类对象实例
3. 用Thread类创建一个对象实例并将第二步中的自定义类对象实例作为参数传给其构造函数
4. 调用Thread类实例的start()方法执行线程。
```java
//MyRunnable.java
public class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println("MyRunnable" + i);
}
}
}
//RunnableTest.java
public class RunnableTest {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start();
for (int i = 0; i < 5; i++) {
System.out.println("MainRunnable" + i);
}
}
}
//运行效果应该跟上面继承Thread类实现多线程效果差不多。
```
> 上述代码也可以通过使用匿名内部类的方式进行简化:
>
> ```java
> public class RunnableTest {
> public static void main(String[] args) {
> new Thread(new Runnable() {
> public void run() {
> for (int i = 0; i < 5; i++) {
> System.out.println("MyRunnable" + i);
> }
> }
> }).start();
> for (int i = 0; i < 5; i++) {
> System.out.println("MainRunnable" + i);
> }
> }
> }
> ```
> **==上面两种方式的比较==**
>
> **继承Thread类**
>
> * 优点直接使用Thread类中的方法代码简单
> * 弊端如果已有父类不可用Java不可多继承)
>
> **实现Runnable接口更常用**:
>
> 与继承Threadl类相比具有以下优势
>
> * 通过创建任务,给线程分配任务实现多线程,更适合多个线程同时执行相同任务的情况
> * 可以避免单继承带来的局限性Java允许实现多个接口但不能继承多个父类
> * 任务和线程分离,提高程序健壮性
> * 后续学到的线程池技术它只接收Runnable类型任务不接收Thread类型线程
> **==Thread类API==**
>
> 1. 常用构造方法
>
> | 构造器 | 描述 |
> | -------------------------------------- | ----------------------- |
> | `Thread()` | 分配新的 `Thread`对象。 |
> | `Thread(Runnable target)` | 分配新的 `Thread`对象。 |
> | `Thread(Runnable target, String name)` | 分配新的 `Thread`对象。 |
> | `Thread(String name)` | 分配新的 `Thread`对象。 |
>
> 2. 常用其他方法
>
> | 变量和类型 | 方法 | 描述 |
> | :-------------- | :------------------------------ | :----------------------------------------------------------- |
> | `long` | `getId()` | 返回此Thread的标识符。 |
> | `String` | `getName()` | 返回此线程的名称。 |
> | `int` | `getPriority()` | 返回此线程的优先级。 |
> | `void` | `setPriority(int newPriority)` | 更改此线程的优先级。 |
> | `Thread.State` | `getState()` | 返回此线程的状态。 |
> | `static Thread` | `currentThread()` | 返回对当前正在执行的线程对象的引用。 |
> | `void` | `start()` | 导致此线程开始执行; Java虚拟机调用此线程的`run`方法。 |
> | `static void` | `sleep(long millis)` | 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数,具体取决于系统计时器和调度程序的精度和准确性。 |
> | `static void` | `sleep(long millis, int nanos)` | 导致当前正在执行的线程休眠(暂时停止执行)指定的毫秒数加上指定的纳秒数,具体取决于系统定时器和调度程序的精度和准确性。 |
> | `void` | `setDaemon(boolean on)` | 将此线程标记为 daemon线程或用户线程。 |
>
> 3. 特殊字段:控制线程抢到时间片的几率
>
> | 变量和类型 | 字段 | 描述 |
> | ------------ | --------------- | -------------------------- |
> | `static int` | `MAX_PRIORITY` | 线程可以拥有的最大优先级。 |
> | `static int` | `MIN_PRIORITY` | 线程可以拥有的最低优先级。 |
> | `static int` | `NORM_PRIORITY` | 分配给线程的默认优先级。 |
>
> 其他的可以参考Java的API手册
### 实现Callable接口
Callable接口代码
```java
public interface Callable<V> {
V call() throws Exception;
}
```
步骤:
1. 创建一个自定义类实现Callable接口并实现其抽象方法call(),编写线程要执行的任务
```java
class XXX implements Callable<T> {
@Override
public <T> call() throws Exception {
return T;
}
}
```
2. 创建FutureTask对象 , 并传入第一步编写的Callable类对象
```java
FutureTask<Integer> future = new FutureTask<>(callable);
```
3. 通过Thread启动线程
```java
new Thread(future).start();
```
```java
//MyCallable.java
import java.util.concurrent.Callable;
public class MyCallable<T> implements Callable<T> {
@Override
public T call() throws Exception {
for (int i = 0; i < 5; i++) {
System.out.println("MyCallable:" + i);
}
return null;
}
}
//CallableTest.java
import java.util.concurrent.FutureTask;
public class CallableTest {
public static void main(String[] args) {
MyCallable<String> mc = new MyCallable<> ();
FutureTask<String> future = new FutureTask<> (mc);
new Thread(future).start();
for (int i = 0; i < 5; i++) {
System.out.println("main" + i);
}
}
}
```
> 上述代码也可以通过使用匿名内部类的方式进行简化:
>
> ```java
> import java.util.concurrent.Callable;
> import java.util.concurrent.FutureTask;
> public class CallableTest {
> public static void main(String[] args) {
> new Thread(new FutureTask<>(new Callable<String>() {
> @Override
> public String call() throws Exception {
> for (int i = 0; i < 5; i++) {
> System.out.println("MyCallable:" + i);
> }
> return null;
> }
> })).start();
> for (int i = 0; i < 5; i++) {
> System.out.println("main" + i);
> }
> }
> }
> ```
>
>
> **Runnable 与 Callable比较**
>
> * 相同点:
> * 都是接口
> * 都可以编写多线程程序
> * 都采用Thread.start()启动线程
>
> * 不同点
> * Runnable没有返回值Callable可以返回执行结果
> * Callable接口的call()允许抛出异常Runnable的run()不能抛出
>
> Callalble接口支持返回执行结果需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执
> 行,如果不调用不会阻塞。
## 多线程的应用实例
### 设置和获取线程名称
`currentThread()` 可以获取当前正在执行的线程对象
```java
//MyRunnable.java
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName());//获取当前线程对象的名称
}
}
//GetThread.java
public class GetThread {
public static void main(String[] args) {
System.out.println(Thread.currentThread().getName());//获取当前线程对象的名称
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable()).start();
new Thread(new MyRunnable(),"answer").start(); //给线程指定一个名称 (方法一)
Thread t = new Thread(new MyRunnable());
t.setName("anotherWay"); //给线程指定一个名称 (方法二)
t.start();
}
}
```
执行结果:
![image-20201020213805266](https://i.loli.net/2020/10/20/DFz1sN5h2wUqyBG.png)
### 线程休眠sleep
`sleep(long millis)`是Thread类的静态方法类名直接调用即可单位ms。
```java
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
System.out.print(i + " ");
Thread.sleep(1000);
}
}
}
```
运行结果每隔1秒打印一个数字。
![](https://i.loli.net/2020/10/20/pIqfd5TD2waWtXo.gif)
> **线程阻塞**:所有较耗时的操作都能称为阻塞。也叫耗时操作。
### 线程的中断
一个线程是一个独立的执行路径,它是否应该结束,**由其自身决定**。
因为线程执行过程会有很多资源需要使用或释放,如果干涉它的结束,很可能导致资源没能来得及释放,一直占用,从而产生无法回收的内存垃圾。
Java以前提供stop()方法可以结束线程,现在已经过时(不再使用)。现在出了新的方法,**给线程打中断标记**`interrupt`)来控制它的结束。
具体方法就是 调用`interrupt()`方法子线程执行时捕获中断异常并在catch块中添加处理释放资源的代码。
如下代码所示main线程执行完后不管子线程是否执行完都中断掉它
```java
//MyRunnable.java
public class MyRunnable implements Runnable{
@Override
public void run() {
//线程任务打印1-10
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {//发现中断标记进入catch块中进行释放资源处理
System.out.println(Thread.currentThread().getName()+":发现中断标记,我自杀了");
return; //为了演示,直接结束
}
}
}
}
//InterruptTest.java
public class InterruptTest {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.setName("myThread");
t1.start();
//main线程 打印1-5
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
t1.interrupt(); //给线程t1添加中断标记
}
}
```
运行结果:
![](https://i.loli.net/2020/10/20/7vUXIGJWRbj4tTH.png)
### 守护线程
线程分为**守护线程**和**用户线程**
- **用户线程**:当一个进程不包含任何存活的用户线程时,进行结束。
- **守护线程**:守护用户线程,当最后一个用户线程结束时,所有守护线程自动死亡。
直接创建的都是用户线程,
设置线程为守护线程:在启动之前设置 ,语法为:`线程对象.setDaemon(true);`。
```java
//MyRunnable.java
public class MyRunnable implements Runnable{
@Override
public void run() {
//线程任务打印1-10
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + "" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
return; //为了演示,直接结束
}
}
}
}
//InterruptTest.java
public class InterruptTest {
public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnable());
t1.setName("myThread");
t1.setDaemon(true);//设置t1为守护线程
t1.start();
//main线程 打印1-5
for (int i = 1; i <= 5; i++) {
System.out.println(Thread.currentThread().getName() + "" + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
```
运行结果
![](https://i.loli.net/2020/10/20/YDGyOnPhEL3eXNz.png)
### 线程安全问题
#### 问题引入
我们先来看个例子三个窗口线程同时卖5张票。
```java
public class Demo1 {
public static void main(String[] args) {
Runnable run = new Ticket();
new Thread(run).start();
new Thread(run).start();
new Thread(run).start();
}
static class Ticket implements Runnable{
private int count = 5; //票数
@Override
public void run() {
while (count > 0) {
//卖票
System.out.println(Thread.currentThread().getName()+"正在卖票");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count--;
System.out.println(Thread.currentThread().getName()+"出票成功,余票:"+count);
}
}
}
}
```
运行结果部分截图:
![](https://i.loli.net/2020/10/21/g31kZ6c4FnywoqQ.png)
我们看到余票出现了负数,显然这是不合理的,这就是线程不安全导致的。出现这种情况的原因:线程争抢,导致线程不安全。 多线程在进行同一卖票任务时,没人干涉,各个窗口疯狂买票,最终导致卖的票超出总票数,余票出现负数。
<font color=red>**线程不安全的原因:**</font>
当多线程并发访问**临界资源**时,如果破坏**原子操作**,可能会造成数据不一致。
- 临界资源:共享资源(同一对象),一次仅允许一个线程使用,才可保证其正确性。
- 原子操作:不可分割的多步操作,被视作一个整体,其顺序和步骤不可打乱或缺省。
多个线程争抢同一个数据,使得数据在判断和使用时出现不一致的情况。那如何解决呢?
解决方法保证一段数据同时只能被一个线程使用排队使用也就是线程同步给线程加锁synchronized
我们有以下三种方法解决线程不安全的问题:同步代码块、同步方法、显示锁
#### 同步代码块
使用synchronized关键字加上一个锁对象来定义一段代码, 这就叫同步代码块
多个同步代码块如果使用**相同的锁对象**, 那么他们就是同步的
语法格式:`synchronized(锁对象) {}`
任何对象都可以作为**锁对象**存在。
还以上面卖票的代码为例,给卖票的线程加锁
![image-20201021174518339](https://i.loli.net/2020/10/21/fcxmMsCzRarQS8P.png)
#### 同步方法
以方法为单位进行加锁。把synchronized关键字修饰在方法中。
还以上面卖票的代码为例写一个synchronized修饰的方法sale()执行卖票任务,
![](https://i.loli.net/2020/10/21/SoCgaNvHtdc6GwX.png)
#### 显式锁
> 上面三种方法中,同步代码块和同步代码都是隐式锁
`Lock l = new ReentrantLock()`:自己创建一把锁
`lock()`:加锁 `unlock()`:解锁
还以上面卖票的代码为例
![](https://i.loli.net/2020/10/21/MdGWmJql95V1uEX.png)
> **显式锁和隐式锁的区别:**
>
> | 区别 | synchronized | lock |
> | ------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
> | 原始构成 | Java关键字由JVM维护是JVM层面的锁 | JDK1.5之后的类使用lock是在调用API是API层面的锁 |
> | 使用方式 | 隐式锁不需要手动获取和释放锁只需要写synchronized不用进行其他操作 | 显式锁,需要手动获取和释放锁,如果没有释放锁,可能会出现死锁 |
> | 等待中断 | 不会中断,除非抛出异常或正常运行完成 | 可以中断1调用设置超时方法tryLock(long timeout ,timeUnit unit)2调用lockInterruptibly()放到代码块中然后调用interrupt()方法可以中断 |
> | 加锁公平 | **非公平锁** | 可以是**公平锁**也可以是**非公平锁**默认是非公平锁。可以在其构造方法传入Boolean值true公平锁false非公平锁 |
> | 绑定多个条件 | 没有。不能精确唤醒线程,要么随机唤醒一个线程,要么唤醒所有等待线程 | 用来实现分组唤醒需要唤醒的线程,可以精确唤醒线程 |
> | 性能 | JDK1.5时性能较低JDK1.6时性能优化与lock相较无异 | JDK1.5时性能更高JDK1.6时synchronized优化赶上lock |
> | 加锁方式 | 线程获取独占锁CPU悲观锁机制只能依靠阻塞等待线程释放锁。在CPU转换线程阻塞时会引起线程上下文切换当竞争锁的线程过多时会引起CPU频繁上下文切换导致效率低下 | 使用乐观锁机制CAS操作 Computer and Swap假设不会发生冲突一旦发生冲突失败就重试直到成功为止。 |
>
> **公平锁**:先来先得,排队执行
>
> **非公平锁**:抢占式的,谁抢到是谁的
> 更多关于线程安全的问题可以看下面这篇文章
>
> [如果你这样回答“什么是线程安全”,面试官都会对你刮目相看(建议珍藏)](https://mp.weixin.qq.com/s/WDeewsvWUEBIuabvVVhweA)
### <font color=red>线程死锁</font>
#### 概述
当两个或两个以上的线程在执行过程中,因为争夺资源而造成的一种相互等待的状态,由于存在一种环路的锁依赖关系而永远地等待下去,如果没有外部干涉,他们将永远等待下去,此时的这个状态称之为死锁。
多个线程相互占用对方的资源的锁,而又相互等对方释放锁,此时若无外力干预,这些线程则一直处于阻塞的假死状态,形成死锁。
举个例子如下图所示在线程A持有锁L并想获得锁M的同时线程B持有锁M并尝试获得锁L那么这两个线程将永远地等待下去这种情况就是死锁形式。
![](https://i.loli.net/2020/10/21/oC9p8qRF7h1d4DS.png)
**死锁产生的条件:**
- **互斥条件**:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用完释放。
- **请求和保持条件**:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
- **不剥夺条件**:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
- **环路等待条件**:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{ABC···Z} 中的A正在等待一个B占用的资源B正在等待C占用的资源……Z正在等待已被A占用的资源。
#### 如何避免死锁
1. 按顺序加锁:如果每个线程都按同一个的加锁顺序这样就不会出现死锁。
2. 给锁加时限:每个线程获取锁的时候加上个时限,如果超过某个时间就放弃锁。
3. 死锁检测:按线程间获取锁的关系检测线程间是否发生死锁,如果发生死锁就执行一定的策略,如终断线程或回滚操作等。
> 更多关于线程死锁的问题可以看下面这篇文章,以上内容也是来自这篇文章:
>
> [多线程 死锁详解](https://mp.weixin.qq.com/s/kvvJ9_xKaOMobaX7PZ5VCQ)
### 多线程通信
Object方法中提供了一些线程间相互通信的方法
| 变量和类型 | 方法 | 描述 |
| ---------- | -------------------------------------- | ------------------------------------------------------------ |
| `void` | `notify()` | 唤醒正在此对象监视器上等待的单个线程。 |
| `void` | `notifyAll()` | 唤醒等待此对象监视器的所有线程。 |
| `void` | `wait()` | 导致当前线程等待它被唤醒,通常是 通知或 中断 。 |
| `void` | `wait(long timeoutMillis)` | 导致当前线程等待它被唤醒,通常是 通知或 中断 ,或者直到经过一定量的实时。 |
| `void` | `wait(long timeoutMillis, int nanos)` | 导致当前线程等待它被唤醒,通常是 通知或 中断 ,或者直到经过一定量的实时。 |
**什么时候需要通信**
多个线程并发执行时, 在默认情况下CPU是随机切换线程的如果我们希望他们有规律的执行, 就可以使用通信。
#### 生产者与消费者
> 看下面代码有Cooker类Waiter类Food类
>
> 厨师cooker为生产者线程服务员waiter为消费者线程食物food为生产与消费的物品
>
> 假设目前只有一个厨师,一个服务员,一个盘子。理想状态是:厨师生产一份饭菜,服务员端走一份,且饭菜的属性未发生错乱;
>
> 厨师可以制作两种口味的饭菜制作100次
>
> 服务员可以端走饭菜100次
```java
public class Demo {
public static void main(String[] args) {
Food f = new Food();
new Cooker(f).start();
new Waiter(f).start();
}
static class Cooker extends Thread{ //生产者线程
private Food f;
public Cooker(Food f){
this.f = f;
}
public void run() {
//生产100个菜
for (int i = 0; i < 100; i++) {
if (i % 2 == 0){
f.setNameAndTaste("菜1","味道1");
} else {
f.setNameAndTaste("菜2","味道2");
}
}
}
}
static class Waiter extends Thread { //消费者线程
private Food f;
public Waiter(Food f){
this.f = f;
}
public void run() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
f.get();
}
}
}
static class Food {
private String name;
private String taste;
public void setNameAndTaste(String name,String taste){ //生产
this.name = name; //先设定名称
try {
Thread.sleep(100); //为使线效果明显,中间休眠一段时间
} catch (InterruptedException e) {
e.printStackTrace();
}
this.taste = taste; //休眠后设定味道
}
public void get(){ //消费
System.out.println("服务员端走的菜名称是:" + name + ",味道:" + taste);
}
}
}
```
运行结果
![](https://i.loli.net/2020/10/21/CAYzM4DNI36Pg7V.png)
原因:我们在设定菜名和味道的`setNameAndTaste`方法中,先设定名称,然后休眠一段时间,再设定的味道,中间休眠的那段时间很可能发生时间片丢失,使得菜属性产生混乱。
**解决方式一**
为了防止在生产过程中setNameAndTaste出现时间片切换可以用synchronized修饰此方法
```java
public synchronized void setNameAndTaste(String name,String taste){
//...
}
public synchronized void get(){ // 消费
//...
}
```
运行结果
![](https://i.loli.net/2020/10/21/HhAMOSIL9Ymn3lE.png)
可以看出依然不符合实际情况这是因为synchronized只是确保了方法内部不会发生线程切换但并不能保证生产一个消费一个的逻辑关系
**解决方式二**
在解决方案一的基础上,进行线程之间的通信
```java
private boolean flag = true; //默认为true表示可以做饭
```
厨师做完饭后喊醒服务员自己睡着。服务员送完饭后喊醒厨师自己睡着将Food类左如下修改
![](https://i.loli.net/2020/10/21/flHwKZ9nbGrg8mT.png)
运行结果,做一道菜,端走一道。
![image-20201021210352200](https://i.loli.net/2020/10/21/m7pIQqgSCZz59HG.png)
## 线程的六种状态
Enum Thread.State描述了六种线程的状态如下表所示
| Enum Constant | 描述 |
| --------------- | -------------------------------------------------- |
| `BLOCKED` | 线程的线程状态被阻塞等待监视器锁定。(阻塞) |
| `NEW` | 尚未启动的线程的线程状态。(创建) |
| `RUNNABLE` | 可运行线程的线程状态。(就绪和运行) |
| `TERMINATED` | 终止线程的线程状态。(消亡) |
| `TIMED_WAITING` | 具有指定等待时间的等待线程的线程状态。(有限期等待) |
| `WAITING` | 等待线程的线程状态。(无限期等待) |
## 线程池Executors
> 普通线程的执行流程:
>
> 创建线程 → 创建任务 → 执行任务 → 关闭线程
>
> 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低 系统的效率,因为频繁创建线程和销毁线程需要时间。 线程池就是一个容纳多个线程的容器,池中的线程可以反复使用,省去了频繁创建和销毁线程对象的操作,节省了大量的时间和资源。
线程池的好处
* 降低资源消耗。
* 提高响应速度。
* 提高线程的可管理性。
Java中有四种线程池(ExecutorService):缓存线程池、定长线程池、单线程线程池、周期性任务定长线程池
### 缓存线程池
长度无限制
执行流程:
1. 判断线程池是否存在空闲线程
2. 存在则使用
3. 不存在,则创建线程 并放入线程池, 然后使用
```java
ExecutorService service = Executors.newCachedThreadPool(); //获取缓存线程池对象
//向线程池中 加入 新的任务
service.execute(new Runnable() {
@Override
public void run() {
//线程任务代码
}
});
```
### 定长线程池
长度是指定的数值
步骤:
1. 判断线程池是否存在空闲线程
2. 存在则使用
3. 不存在空闲线程,线程池未满的情况下,则创建线程 并放入线程池, 然后使用
4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
```java
ExecutorService service = Executors.newFixedThreadPool(2);
service.execute(new Runnable() {
public void run() {
//线程任务代码
}
});
```
### 单线程线程池
步骤:
1. 判断线程池的那个线程是否空闲
2. 空闲则使用
3. 不空闲则等待池中的单个线程空闲后使用
```java
ExecutorService service = Executors.newSingleThreadExecutor();
service.execute(new Runnable() {
public void run() {
//线程任务代码
}
});
```
### 周期性任务定长线程池
步骤:
1. 判断线程池是否存在空闲线程
2. 存在则使用
3. 不存在空闲线程,且线程池未满的情况下,则创建线程,并放入线程池后使用
4. 不存在空闲线程,且线程池已满的情况下,则等待线程池存在空闲线程
周期性任务执行时:定时执行, 当某个时机触发时, 自动执行某任务
```java
ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
/**
* 定时执行
* 参数1. runnable类型的任务
* 参数2. 时长数字 5
* 参数3. 时长数字的单位 TimeUnit.SECONDS
*/
service.schedule(new Runnable() {
public void run() {
//线程任务代码
}
},5,TimeUnit.SECONDS);
/**
* 周期执行
* 参数1. runnable类型的任务
* 参数2. 时长数字(延迟执行的时长) 5
* 参数3. 周期时长(每次执行的间隔时间) 2
* 参数4. 时长数字的单位 TimeUnit.SECONDS
*/
service.scheduleAtFixedRate(new Runnable() {
public void run() {
//线程任务代码
}
},5,2,TimeUnit.SECONDS);
```

View File

@ -0,0 +1,375 @@
---
title: Java异常处理
date: 2020-10-11 14:24:00
tags:
- Java
- 面向对象
categories:
- Java基础
---
## 什么是异常
异常是在程序中导致程序中断运行的一种指令流。
先来看如下代码
```java
public class ExceptionDemo{
public static void main(String[] args){
int i = 10 ;
int j = 0 ;
System.out.println("============= 计算开始 =============") ;
System.out.println(i + "/" + j + "=" + i / j);
System.out.println("============= 计算结束 =============") ;
}
};
```
<!--more-->
运行结果:
```java
============= 计算开始 =============
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ExceptionDemo01.main(ExceptionDemo01.java:6)
```
以上的代码在`System.out.println(i + "/" + j + "=" + i / j);`位置处产生了异常`ArithmeticException(算术异常)`,一旦产生异常之后,异常之后的语句将不再执行了,所以现在的程序并没有正确的执行完毕之后就退出了。
那么,为了保证程序出现异常之后仍然可以正确的执行完毕,所以要采用异常的处理机制。
## 异常处理
如果要想对异常进行处理,则必须采用标准的处理格式,处理格式语法如下:
```java
try{
// 有可能发生异常的代码段
}catch(异常类型1 对象名1){
// 异常的处理操作
}catch(异常类型2 对象名2){
// 异常的处理操作
} ...
finally{
// 异常的统一出口
}
```
将开头的代码用try-catch处理
```java
public class ExceptionDemo{
public static void main(String[] args){
int i = 10 ;
int j = 0 ;
System.out.println("============= 计算开始 =============") ;
try{
System.out.println(i+ "/" + j + "=" + i /j);
}catch(ArithmeticException e){
System.out.println("除数不能为0");
}
System.out.println("============= 计算结束 =============") ;
}
};
```
运行结果
```bash
============= 计算开始 =============
除数不能为0
============= 计算结束 =============
```
### try+catch的处理流程
1、 一旦产生异常,则系统会自动产生一个异常类的实例化对象。
2、 那么此时如果异常发生在try语句则会自动找到匹配的catch语句执行如果没有在try语句中则会将异常抛出抛给调用方法者
3、 所有的catch根据方法的参数匹配异常类的实例化对象如果匹配成功则表示由此catch进行处理。
![](https://i.loli.net/2020/10/10/bVzw1mud4eif7ot.png)
### finally
在进行异常的处理之后在异常的处理格式中还有一个finally语句那么此语句将作为异常的统一出口<span style="color:red">不管是否产生了异常,最终**必然都要**执行此段代码</span>
> finally例子1
>
> ```java
> public class ExceptionDemo {
> public static void main(String[] args){
> try {
> System.out.println(1);
> System.out.println(2);
> return;
> }catch (Exception e) {
> return;
> }finally {
> System.out.println("finally代码块中的内容");
> }
> }
> };
> ```
>
> 运行测试结果说明即使在try和catch中return在准备返回值与跳出函数之间仍然会执行finally中的语句
>
> ![image-20201010164546702](https://i.loli.net/2020/10/10/x5eOw9uGgMRCEdZ.png)
>
> finally例子2
>
> ```java
> public class ExceptionDemo {
> public static void main(String[] args){
> Person p = testFinally();
> System.out.println(p.age); //28
> }
> public static Person testFinally(){
> Person p = new Person();
> try {
> p.age = 18;
> return p;
> }catch (Exception e) {
> return null;
> }finally {
> p.age = 28;
> }
> }
> static class Person{
> int age;
> }
> };
> ```
>
> finally例子3
>
> ```java
> public class ExceptionDemo {
> public static void main(String[] args){
> int a = testFinally();
> System.out.println(a); //10
>
> }
> public static int testFinally(){
> int a = 10;
> try {
> return a;
> }catch (Exception e) {
> return 0;
> }finally {
> a = 20;
> }
> }
> };
> ```
>
> 注意例子2和例子3我们 testFinally() 方法一个返回的是引用数据类型一个返回的是基本数据类型。例子3中返回非引用数据类型时return 备份的就是数据10所以运行结果是10不过此时栈中a的数据还是被改成20了。而在例子2中我们return备份的是引用类型对象 p 在堆中的地址存放在堆中那个地址的age被改为了28当我们return 通过地址去找age时就是会返回28。
### 异常处理真实场景举例
```java
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionDemo2 {
public static void main(String[] args) {
int num = menu();
System.out.println("您选择的序号是" + num);
}
public static int menu(){
System.out.println("请根据提示,选择功能序号:");
System.out.println("0.退出\n1.增\n2.删\n3.改");
Scanner input = new Scanner(System.in);
int num = -1;
try {
num = input.nextInt();
if (num<0 || num>3){
System.out.println("输入的序号必须是0/1/2/3");
return menu();//如果数字范围超过预期,递归重新调用此函数
}
return num;
}catch (InputMismatchException e){
System.out.println("输入必须是数字");
return menu(); //如果输入非数字,递归重新调用此函数
}
}
}
```
运行效果测试:
![image-20201010161246734](https://i.loli.net/2020/10/10/lKxIRXjcQ4SzuGh.png)
## 异常体系结构
异常指的是Exception Exception类 在Java中存在一个父类Throwable可能的抛出
Throwable存在两个子类
1. Error表示的是错误是JVM发出的错误操作,只能尽量避免,无法用代码处理。
2. Exception一般表示所有程序中的错误所以一般在程序中将进行try…catch的处理。
![](https://i.loli.net/2020/10/10/5WiUkG6aMdAOwYo.png)
> 多异常捕获的注意点:
>
> 1. 捕获更粗的异常不能放在捕获更细的异常之前。
> 2. 如果为了方便则可以将所有的异常都使用Exception进行捕获。
>
> 特殊的多异常捕获写法:
>
> ```java
> catch(异常类型1 |异常类型2 对象名){
> //表示此块用于处理异常类型1 和 异常类型2 的异常信息
> }
> ```
>
> ```java
> import java.util.Scanner;
>
> public class ExceptionDemo {
> public static void main(String[] args){
> try {
> Scanner input = new Scanner(System.in);
> System.out.println("请输入一个数字:");
> int x = input.nextInt();
> System.out.println("请再输入一个数字:");
> int y = input.nextInt();
> System.out.println(x/y);
> }catch (InputMismatchException | ArithmeticException e) { //格式一
> System.out.println("输入错误");
> }
> /*
> catch(RuntimeException e或Exception e){ //扩大异常的形态范围来捕获 ,格式二
> System.out.println("输入错误");
> }
> */
> System.out.println("程序执行完毕,正常结束");
> }
> };
> ```
## throws和throw关键字
###throws
在程序中异常的基本处理已经掌握了但是随异常一起的还有一个称为throws关键字此关键字主要在方法的声明上使用表示方法中不处理异常而交给调用处处理。格式如下
```java
返回值 方法名称()throws Exception{
}
```
如果是因为传入的参数导致异常的发生则可以通过throws抛出异常。通常是谁调用谁处理
如下代码,只有传入参数出错,程序才会出错。
![image-20201010184935241](https://i.loli.net/2020/10/10/XwxopzQTY85asmi.png)
我们可以用谁调用谁处理的策略使用throws关键字来处理异常
![image-20201010191247867](https://i.loli.net/2020/10/10/t2qHGzpw1Lgfr7s.png)
###throw
throw关键字表示在程序中人为的抛出一个异常因为从异常处理机制来看所有的异常一旦产生之后实际上抛出的就是一个异常类的实例化对象那么此对象也可以由throw直接抛出。真正应用时自己造异常还是比较麻烦的之前加判断也可以出现相同的效果所以用的较少
代码: `throw new Exception("抛着玩的。");`
看下面的代码
```java
public class ExceptionDemo8 {
public static void main(String[] args){
Person p = new Person();
p.setAge(-1);//传入非法参数
}
};
class Person {
int age;
public void setAge(int age) { //处理异常时机:谁调用谁处理
//之前在设计此函数时当用户输入了不合理时自动设为1
//但用户在没有任何提示的情况下,输入和实际展示不一致,者本身就是异常
if (age < 0 || age > 150){
//this.age = 1;
//所以在发生异常时,需要告诉调用函数,发生了什么问题,而不是自己默默处理
throw new RuntimeException("年龄不合理");
}else{
this.age = age;
}
}
}
```
运行结果:
![image-20201010173420321](https://i.loli.net/2020/10/10/7ciUMJSWOrK5aE9.png)
## RuntimeExcepion与Exception的区别
注意观察如下方法的源码:
Integer类` public static int parseInt(String text)throws NumberFormatException`
此方法抛出了异常, 但是使用时却不需要进行try…catch捕获处理原因
因为`NumberFormatException`并不是`Exception`的直接子类,而是`RuntimeException`的子类,<span style="color:red">只要是`RuntimeException`的子类则表示程序在操作的时候可以不必使用try…catch进行处理如果有异常发生则由JVM进行处理。</span>当然也可以通过try…catch处理。
## 自定义异常类
> 编写一个类, 继承Exception并重写一参构造方法 即可完成自定义**受检异常**类型。受检异常必须明确的处理或者抛出,否则编译不通过
>
> 编写一个类, 继承RuntimeExcepion并重写一参构造方法 即可完成自定义**运行时异常(非受检异常)**类型。
>
> 例如:
>
> ```java
> class MyException extends Exception{ // 继承Exception表示一个自定义异常类
> public MyException(String msg){
> super(msg) ; // 调用Exception中有一个参数的构造
> }
> };
> ```
>
> 自定义异常可以做很多事情, 例如:
>
> ```java
> class MyException extends Exception{
> public MyException(String msg){
> super(msg) ;
> //在这里给维护人员发短信或邮件, 告知程序出现了BUG。
> }
> };
> ```
## 异常处理常见题目
1. **try-catch-finally 中哪个部分可以省略?**
答: catch和finally可以省略其中一个 catch和finally不能同时省略
注意:格式上允许省略catch块, 但是发生异常时就不会捕获异常了,我们在开发中也不会这样去写代码.
2. **try-catch-finally 中,如果 catch 中 return 了finally 还会执行吗?**
finally中的代码会执行
> 详解:
>
> 执行流程:
>
> 1. 先计算返回值, 并将返回值存储起来, 等待返回
> 2. 执行finally代码块
> 3. 将之前存储的返回值, 返回出去;
>
> 注意:
>
> 1. 返回值是在finally运算之前就确定了并且缓存了不管finally对该值做任何的改变返回的值都不会改变
> 2. finally代码中不建议包含return因为程序会在上述的流程中提前退出也就是说返回的值不是try或catch中的值
> 3. 如果在try或catch中停止了JVM则finally不会执行。例如停电或通过如下代码退出
> JVM`System.exit(0);`

400
source/_posts/Java数组.md Normal file
View File

@ -0,0 +1,400 @@
---
title: Java数组
date: 2020-05-24 18:59:37
tags:
- Java
categories:
- Java基础
---
## 数组概述
**`数组的定义:`**
* 数组是<span style="color:red">相同类型数据</span>的有序集合。
* 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。
* 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。
<!--more-->
### 数组的声明创建
首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法:
```java
dataType[] arrayRefVar; //首选的方法
dataType arrayRefVar[]; //效果相同,但不是首选方法,不推荐使用
```
Java语言使用`new` 操作符来创建数组,语法如下:
```java
dataType[] arrayRefVar = new dataType[arraySize];
```
数组的元素是通过索引访问的,<span style="color:red">数组索引从**0**开始</span>
获取数组长度:`arrays.length`
声明时数组在内存中并不存在,只有在创建数组时,才会在内存中为数组分配指定的空间。
### Java内存分析
![java内存](https://i.loli.net/2020/05/23/pEowZelcCNFGzQ3.png)
`数组在内存中的创建过程:`
1. 在声明数组时会在栈中压入数组名
2. 创建数组时会在堆中开辟指定的空间用来存放数组
3. 给数组赋值,将值存放在堆中数组对应的空间里
![数组在内存中的创建过程](https://i.loli.net/2020/05/23/QGIF8zbnEcasDvg.png)
### 数组的三种初始化
* **静态初始化**
```java
int[] a = {1,2,3};
Man[] mans ={new Man(1,1),new Man(2,2)};
```
* **动态初始化**
```java
int[] a = new int[2]; //创建数组 默认初始化
a[0] = 1;
a[1] = 2;
```
* **数组的默认初始化**
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
### 数组的四个基本特点
* 其长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
* 其元素必须是<span style="color:red">相同类型</span>,不允许出现混合类型。
* 数组中的元素可以是任何数据类型,包括基本类型和引用类型。
* 数组变量属引用类型数组也可以看成是对象数组中的每个元素相当于该对象的成员变量。数组本身就是对象Java中对象是在堆中的因此数组无论保存原始类型还是其他对象类型<span style="color:red">数组对象本身是在堆中的</span>
### 数组边界
下标的合法区间:[0,length-1],如果越界就会报错;
```java
public static void main(String[] args){
int[] a = new int[2];
System.out.println(a[2]); //报错
}
```
<span style="color:red">ArraylndexOutOfBoundsException数组下标越界异常</span>
> **`小结`**
>
> * 数组是相同数据类型(数据类型可以为任意类型)的有序集合
> * 数组也是对象。数组元素相当于对象的成员变量
> * 数组长度的确定的不可变的。如果越界则报ArraylndexOutofBounds
## 数组的使用
数组一般可以配合循环来使用。
```java
public class ArrayDemo {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
//打印全部的数组元素
for (int i = 0; i < arrays.length; i++) {
System.out.println(arrays[i]);
}
//打印所有元素的和
int sum = 0;
for (int i = 0; i < arrays.length; ++i) {
sum += arrays[i];
}
System.out.println("sum="+sum);
//查找最大最小元素
int max = array[0];//创建变量,存储遍历数组时发现的最大值,
//初始值赋为数组中第一个元素而不赋为0是为了避免数组中没有比0大的值这样就会输出错误的值
int min = array[0]
for (int i = 1; i < arrays.length; i++) {
max = max > arrays[i] ? max : arrays[i];
min = min < arrays[i] ? min : arrays[i]
}
System.out.println("max="+max+"\nmin="+"min");
}
}
```
### for-each循环(增强型for循环)
```java
public class ArrayDemo {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
for(int array : arrays){ //这种方式没有下标,适合打印输出
System.out.println(array);
}
}
}
```
### 数组作方法入参和作返回值
```java
public class ArrayDemo {
public static void main(String[] args) {
int[] arrays = {1,2,3,4,5};
int[] arraysReverse = reverse(arrays);
printArray(arraysReverse);
}
//打印数组元素
public static void printArray(int[] arrays){ //数组作为方法的传入参数
for (int i = 0; i < arrays.length; i++){
System.out.print(arrays[i]+" ");
}
}
//反转数组
public static int[] reverse(int[] arrays){
int[] result = new int[arrays.length];
for (int i = 0; i < arrays.length; i++){
result[result.length-i-1] = arrays[i];
}
return result; //数组作为返回值
}
}
```
### 数组的常用算法
####冒泡排序
![冒泡排序](https://i.loli.net/2020/05/24/QoRPrY2VfzcnhwE.gif)
如果遇到相等的值不进行交换,那这种排序方式是稳定的排序方式。
原理:比较两个相邻的元素,将值大的元素交换到右边
思路:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
算法分析:
N个数字要排序完成总共进行N-1趟排序每i趟的排序次数为(N-i)次,所以可以用双重循环语句,外层控制循环多少趟,内层控制每一趟的循环次数
冒泡排序的优点:每进行一趟排序,就会少比较一次,因为每进行一趟排序都会找出一个较大值。如上例:第一趟比较之后,排在最后的一个数一定是最大的一个数,第二趟排序的时候,只需要比较除了最后一个数以外的其他的数,同样也能找出一个最大的数排在参与第二趟比较的数后面,第三趟比较的时候,只需要比较除了最后两个数以外的其他的数,以此类推……也就是说,没进行一趟比较,每一趟少比较一次,一定程度上减少了算法的量。
时间复杂度
1.如果我们的数据正序只需要走一趟即可完成排序。所需的比较次数C和记录移动次数M均达到最小值$C_{min}=n-1$$M_{min}=0$;所以冒泡排序最好的时间复杂度为O(n)。
2.如果很不幸我们的数据是反序的则需要进行n-1趟排序。每趟排序要进行n-i次比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置。在这种情况下,比较和移动次数均达到最大值:
$$C_{max} =\cfrac{n(n-1)}{2} = O(n^2)$$
$M_{max} =\cfrac{3n(n-1)}{2} = O(n^2)$
综上所述:冒泡排序总的平均时间复杂度为:$O(n^2)$ ,时间复杂度和数据状况无关。
> Java代码实现
>
> ```java
> //冒泡排序
> public static int[] bubbleSort(int[] array){
> int temp = 0;
> //外层循环控制比较的轮次 : length-1轮
> for (int i = 0; i < array.length-1; i++){
> //内层循环控制每轮比较的次数
> //第i轮i从0开始计算比较次数为length-i-1
> for (int j = 0; j < array.length-1-i; j++) {
> if (array[j+1]<array[j]){
> temp = array[j];
> array[j] = array[j+1];
> array[j+1] = temp;
> }
> }
> }
> return array;
> }
> ```
#### 二分查找(折半查找)
**概述**
二分查找也称折半查找Binary Search它是一种效率较高的查找方法。但是二分查找要求数组数据必须采用顺序存储结构有序排列。
**原理 **
首先,假设数组中元素是按升序排列,将数组中间位置的数据与查找数据比较,如果两者相等,则查找成功;否则利用中间位置记录将数组分成前、后两个子数组,如果中间位置数据大于查找数据,则进一步查找前子数组,否则进一步查 找后子数组。
重复以上过程,直到找到满足条件的数据,则表示查找成功, 直到子数组不存在为止,表示查找不成功。
> Java代码实现
>
> ```java
> public class Demo5 {
>
> /**
> * 二分查找(折半查找)
> */
> public static void main(String[] args) {
> //定义一个有序数组
> int[] nums = {10,20,30,40,50,60,70,80,90};
> //要查找的数据
> int num = 20;
> bubbleSort(nums,num);
>
> System.out.println("位置:"+centerIndex);
>
> }
> }
> public int binarySearch(int[] arrayint num){
> //1. 最小范围下标
> int minIndex = 0;
> //2. 最大范围下标
> int maxIndex = array.length-1;
> //3. 中间数据下标
> int centerIndex = (minIndex+maxIndex)/2;
> while(true) {
> System.out.println("循环了一次");
> if(array[centerIndex]>num) {
> //中间数据较大
> maxIndex = centerIndex-1;
> }else if(array[centerIndex]<num) {
> //中间数据较小
> minIndex = centerIndex+1;
> }else {
> //找到了数据 数据位置centerIndex
> break;
> }
>
> if(minIndex > maxIndex) {
> centerIndex = -1;
> break;
> }
> //当边界发生变化, 需要更新中间下标
> centerIndex = (minIndex+maxIndex)/2;
> }
> return centerIndex;
> }
> ```
####
## 多维数组
多维数组可以看成是数组的数组,比如二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组。
### 二维数组
```java
int[][] a = new int[2][5] //二维数组a可以看成一个两行5列的数组
```
![](https://i.loli.net/2020/05/24/qOGaBP61eo5mVdU.png)
```java
public class ArrayDemo {
public static void main(String[] args) {
int[][] arrays= {{1,2},{2,3},{3,4},{4,5}};
//将数组遍历打印出来
for (int i = 0; i < arrays.length; i++){
for (int j = 0; j < arrays[i].length; j++){
System.out.print(arrays[i][j]+" ");
}
}
}
```
## Java的Arrays类
数组的工具类`java.util.Arrays`
由于数组对象本身并没有什么方法可以供我们调用但API中提供了一个工具类Arrays供我们使用从而可以对数据对象进行一些基本的操作。
Arrays类中的方法都是static修饰的静态方法在使用的时候可以直接使用类名进行调用而“不用”使用对象来调用注意是“不用”而不是“不能”
Arrays类具有以下**常用**功能
* 给数组赋值通过fill方法。
* 对数组排序:通过 sort 方法,按升序。
* 比较数组通过equals 方法比较数组中元素值是否相等。
* 查找数组元素通过binarySearch 方法能对排序好的数组进行二分查找法操作。
具体使用可参考[JDK文档](https://www.matools.com/api/java8)
## 稀疏数组
当一个数组中大部分元素为0或者为同一值的数组时可以使用**稀疏数组**来保存该数组。
稀疏数组的处理方式是:
* 记录数组一共有几行几列,有多少个不同值
* 把具有不同值的元素的行列及值记录在一个小规模的数组中,从而缩小程序的规模
> 如下图:左边是原始数组,右边是稀疏数组
>
> ![](https://i.loli.net/2020/05/24/4HsMGcvahmbUk72.png)
>
> | | 行 | 列 | 值 | 含义 |
> | :--: | :--: | :--: | :--: | :-------------------------------------: |
> | [0] | 6 | 7 | 8 | 表示这是一个6行7列的数组有效值有 8 个 |
> | [1] | 0 | 3 | 22 | 第一个有效值位于第0行第3列值为22 |
> | [2] | 0 | 6 | 15 | 第二个有效值位于第0行第6列值为15 |
> | [3] | 1 | 1 | 11 | 第三个有效值位于第1行第1列值为11 |
> | [4] | 1 | 5 | 17 | 第四个有效值位于第1行第5列值为17 |
> | [5] | 2 | 3 | -6 | 第五个有效值位于第2行第3列值为-6 |
> | [6] | 3 | 5 | 39 | 第六个有效值位于第3行第5列值为39 |
> | [7] | 4 | 0 | 91 | 第七个有效值位于第4行第0列值为91 |
> | [8] | 5 | 2 | 28 | 第八个有效值位于第5行第2列值为28 |
```java
/**** 转为稀疏数组 ****/
public static int[][] toSparseArray(int[][] arr){
//获取有效值的个数
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if (arr[i][j] != 0) {
sum++;
}
}
}
//新建一个稀疏数组
int[][] arr2 = new int[sum+1][3];
arr2[0][0] = arr.length;
arr2[0][1] = arr[0].length;
arr2[0][2] = sum;
//遍历arr,将非零的值的信息,存放入稀疏数组中
int count = 0;
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
if(arr[i][j] != 0){
count++;
arr2[count][0] = i;
arr2[count][1] = j;
arr2[count][2] = arr[i][j];
}
}
}
return arr2;
}
/**** 稀疏数组转为普通数组 ****/
public static int[][] sparseToArray(int[][] arr){
//读取稀疏数组,并新建一个数组
int[][] arr2 = new int[arr[0][0]][arr[0][1]];
//还原稀疏数组
for (int i = 1; i < arr.length; i++) {
arr2[arr[i][0]][arr[i][1]] = arr[i][2];
}
return arr2;
}
```

151
source/_posts/Java方法.md Normal file
View File

@ -0,0 +1,151 @@
---
title: Java方法
date: 2020-05-30 21:32:41
tags:
- Java
categories:
- Java基础
---
## 方法概述
Java方法是语句的集合它们在一起执行一个功能。
* 方法是解决一类问题的步骤的有序组合
* 方法包含于类或对象中
* 方法在程序中被创建,在其他地方被引用
<!-- more -->
**设计方法的原则:**
方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的<span style="color:red">原子性就是一个方法只完成1个功能这样利于我们后期的扩展</span>
**方法的命名规范:**
首字母小写和驼峰原则run()runRun()。
## 方法的定义及调用
### 方法定义
Java的方法类似于其它语言函数是一段用来完成特定功能的代码片段一般情况下定义一个方法包含以下语法
<span style="color:red">方法包含一个方法头和一个方法体。</span>下面是一个方法的所有部分:
* <span style="color:red">修饰符</span>:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
* <span style="color:red">返回值类型</span>方法可能会返回值。returnValueType是方法返回值的数据类型。有些方法执行所需的操作但没有返回值。在这种情况下returnValueType 是关键字void。
* <span style="color:red">方法名</span>:是方法的实际名称。方法名和参数表共同构成方法签名。
* <span style="color:red">参数类型</span>:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
* 形式参数:在方法被调用时用于接收外界输入的数据。
* 实参:调用方法时实际传给方法的数据。
* <span style="color:red">方法体</span>:方法体包含具体的语句,定义该方法的功能。
* <span style="color:red">返回值</span>如果返回值类型不为void那么需要在方法体的最后return返回值遇到return即结束方法。
```java
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
```
### 方法调用
调用方法:对象名.方法名(实参列表)
Java 支持两种调用方法的方式,根据方法是否返回值来选择。
* 当方法返回一个值的时候,方法调用通常被当做一个值。例如:
```java
int larger = max(20,30);
```
* 如果方法返回值是void方法调用一定是一条语句。
```java
System.out.println("Hello");
```
## 方法重载
重载就是在一个类中,有相同的函数名称,但形参不同的函数。
**方法的重载的规则:**
* 方法名称必须相同。
* 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
* 方法的返回类型可以相同也可以不相同。·仅仅返回类型不同不足以成为方法的重载。
**实现理论:**
方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
## 命令行传参
有时候你希望运行一个程序时候再传递给它消息。这要靠传递命令行参数给main()函数实现。
```java
public class Demo03{
public staticvoid) main(String args[]){
for(int i = 0;i < args.length;i++){
System.out.println("args["+ i +"]:"+args[i]);
}
}
}
```
![](https://i.loli.net/2020/05/30/ZSfx6b4NPU8Xdhe.png)
## 可变参数
JDK 1.5开始Java支持传递同类型的可变参数给一个方法。
在方法声明中,在指定参数类型后加一个省略号(…)。
一个方法中只能指定**一个**可变参数,它必须是方法的**最后一个参数**。任何普通的参数必须在它之前声明。
```java
public static void printMax(double... numbers){
if(numbers.length==0){
System.out.println("No argument passed");
return;
}
double result=numbers[0];
//排序!
for(int i = 1;i < numbers.length;i++){
if(numbers[i]>result){
result=numbers[i];
}
}
System.out.println("The max value is "+result);
}
```
## <span style="color:red">递归</span>
A方法调用B方法我们很容易理解
**递归就是:**A方法调用A方法就是自己调用自己
利用递归可以用简单的程序来解决一些复杂的问题。它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。
**递归结构包括两个部分:**
* <span style="color:red">边界(递归头)</span>:什么时候不调用自身方法。如果没有头,将陷入死循环。
* <span style="color:red">递归体</span>:什么时候需要调用自身方法。
```java
public static int factorial(int n){
if(n == 1){ //边界
return 1;
}else{
n = n*factorial(n-1); //递归
return n;
}
}
```

126
source/_posts/Java泛型.md Normal file
View File

@ -0,0 +1,126 @@
---
title: Java泛型
date: 2020-10-24 16:21:15
tags:
- Java
- 面向对象
categories:
- Java基础
---
### 概述
泛型,即“参数化类型”。就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
<!-- more -->
> **注意:**
>
> 在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型只在编译阶段有效。在编译过程中正确检验泛型结果后会将泛型的相关信息擦出并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说泛型信息不会进入到运行时阶段。
>
> **作用:**
>
> 1. 提高代码复用率
> 2. 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
### 使用
#### 泛型类
```java
//定义一个泛型类:
public class ClassName<T>{
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
//使用该类
public class Main {
public static void main(String[] args) {
ClassName<String> val1 = new ClassName<> (); //在使用时指定为具体的类型
val1.setData("");
ClassName<Integer> val2 = new ClassName<> ();
val2.setData(1);
}
}
```
#### 泛型接口
```java
public interface IntercaceName<T>{
T getData();
}
//实现接口时,可以选择指定泛型类型,也可以选择不指定, 如下:
//指定类型:
public class Interface1 implements IntercaceName<String> {
private String text;
@Override
public String getData() {
return text;
}
}
//不指定类型:
public class Interface1<T> implements IntercaceName<T> {
private T data;
@Override
public T getData() {
return data;
}
}
```
#### 泛型方法
```java
private static <T> T 方法名(T a, T b) {} //T只在方法内有效
```
```java
public class Demo {
public static void main(String[] args) {
print("haha");
print(11212);
}
public static <T> void print(T a){ //方法内的泛型只在方法内有效
System.out.println(a);
}
}
```
### 限制泛型类型
在使用泛型时, 可以指定泛型的限定区域
- 例如: 必须是某某类的子类或 某某接口的实现类,格式:
`<T extends 类或接口1 & 接口2>`
![image-20201013115930582](https://i.loli.net/2020/10/13/CjxYoEDT42qc8KR.png)
### 泛型中的通配符
类型通配符是使用`?`代替方法具体的类型实参。
1. `<? extends Parent>` 指定了泛型类型的上届
2. `<? super Child>` 指定了泛型类型的下届
3. `<?>` 指定了没有限制的泛型类型
![](https://i.loli.net/2020/10/13/J2DuWzcF4KIa5tl.png)
> ### 补充
>
> 如果需要 ,我们可以指定多个泛型,中间用 `,`隔开即可
>
> ```java
> public class ClassName<T,E,A,B>{
> private T data1;
> private E data2;
> private A data3;
> private B data4;
> }
> ```

View File

@ -0,0 +1,283 @@
---
title: Java流程控制
date: 2020-05-19 20:00:28
tags:
- Java
categories:
- Java基础
---
## 用户交互Scanner
java.util.Scanner是Java5的新特征我们可以通过Scanner 类来获取用户的输入。
<!--more-->
```java
Scanner s = new Scanner(System.in);
if (s.hasNext){
type name = s.next()
}
if (s.hasNextLine){
type name = s.nextLine()
}
s.close()
```
通过 Scanner类的next()与nextLine()方法获取输入的字符串,在读取前我们一般需要使用 hasNext()与hasNextLine()判断是否还有输入的数据。
> <span style="color:red">凡是属于IO流的类如果不关闭会一直占用资源要习惯用完就关掉.</span>
下面来看一下`next()`方法和`nextLine()`方法的区别
`next()`:
* 一定要读取到有效字符后才可以结束输入。
* 对输入有效字符之前遇到的空白next()方法会自动将其去掉。
* 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符。
* <span style="color:red">next()不能得到带有空格的字符串。</span>
`nextLine()`:
* 以Enter为结束符也就是说nextLine()方法返回的是输入回车之前的所有字符。
* 可以获得空白。
```java
import java.util.Scanner; //导入Scanner工具类
public class Test {
public static void main(String[] args) {
//创建扫描器Scanner对象用于接收键盘数据
Scanner in1 = new Scanner(System.in);
Scanner in2 = new Scanner(System.in);
//in1和in2都输入“hello world”
//判断用户有没有输入字符串
if(in1.hasNext()){
//使用next()方法接收
String str1 = in1.next();
System.out.println("用next()方法接收的输出:" + str1);
}
if(in2.hasNextLine()){
//使用nextLine()方法接收
String str2 = in2.nextLine();
System.out.println("用nextLine()方法接收的输出:" + str2);
}
//凡是属于IO流的类如果不关闭会一直占用资源要习惯用完就关掉
in1.close();
in2.close();
}
}
```
上面代码运行结果如图所示:
<img src="https://i.loli.net/2020/05/17/Bxt5UXKyWm1co3v.png" style="zoom:80%;" />
scanner工具中还有hasNextInt()、hasNextFloat()等方法验证输入的类型nextInt()、nextFloat()接收相关类型的输入。
> 拓展说明:
>
> `print()`和`println()`的区别:
>
> `println()`:输出完会换行
>
> `print()`:输出完不会换行,内容都输出在一行
>
>
## 顺序结构
JAVA的基本结构就是顺序结构除非特别指明否则就按照顺序一句一句执行。
顺序结构是最简单的算法结构。
<img src="https://i.loli.net/2020/05/17/z5DBQHsrjbfiJMC.png" style="zoom: 50%;" />
语句与语句之间,框与框之间是按从上到下的顺序进行的,它是由若干个依次执行的处理步骤组成的,<span style="color:red">它是任何一个算法都离不开的一种基本算法结构。</span>
## 选择结构
### `if`选择结构
#### `if`单选择结构
我们很多时候需要去判断一个东西是否可行,然后我们才去执行,这样一个过程在程序中用`if`语句来表示。
<img src="https://i.loli.net/2020/05/19/QfS8e5un3JXVdyk.png" style="zoom: 50%;" />
```java
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}
```
#### `if`双选择结构
那现在有个需求公司要收购一个软件成功了给人支付100万元失败了自己找人开发。这样的需求用一个`if`就搞不定了,我们需要有两个判断,需要一个双选择结构,所以就有了`if-else`结构。
<img src="https://i.loli.net/2020/05/19/Ws7XgdF2jonTQfB.png" style="zoom: 67%;" />
```java
if(布尔表达式){
//如果布尔表达式为true将执行的语句
}else{
//如果布尔表达式为false将执行的语句
}
```
####`if`多选择结构
我们发现不管是单选择结构还是双选择结构都不符合实际情况真实的情况还可能存在ABCD存在区间多级判断。比如90-100就是A80-90就是B..等等,在生活中我们很多时候的选择也不仅仅只有两个,所以我们需要一个多选择结构来处理这类问题!
<img src="https://i.loli.net/2020/05/19/2NQ6qmIyFrUYE8i.png" style="zoom: 67%;" />
```java
if(布尔表达式1){
//如果布尔表达式1为true将执行的语句
}else if(布尔表达式2){
//如果布尔表达式2为true将执行的语句
}else{
//如果以上条件都不满足将执行的语句
}
```
####嵌套的`if`结构
使用嵌套的`if...else` 语句是合法的。也就是说你可以在另一个`if `或者`else if `语句中使用`if`或者`else if` 语句。你可以像`if `语句一样嵌套 `else if...else`。
**嵌套 if 语句**,只有当外层 if 的条件成立时,才会判断内层 if 的条件。
```java
if(布尔表达式1){
//如果布尔表达式1为true
if(布尔表达式2){
//如果布尔表达式2为true将执行的语句
}else{
//如果布尔表达式2为false将执行的语句
}
}else{
//如果布尔表达式1为false 将执行的语句
}
```
### `swich`多选择结构
多选择结构还有一个实现方式就是`switch case` 语句。
`switch case` 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。
```java
switch(expression){
case value:
//语句
break;
case value:
//语句
break;
//可以有任意数量的case语句
default:
//语句
}
```
switch 语句中的变量类型可以是:
* byte、short、int 或者char。
* 从Java SE7开始`switch` 支持字符串 String 类型了,同时 `case`标签必须为字符串常量或字面量。
## 循环结构
### `while`循环
```java
while(布尔表达式){
//循环内容
}
```
* 只要布尔表达式为true循环就会一直执行下去。
* <span style="color : red">大多数情况是需要让循环停下来的,我们可以以让表达式失效的方式来结束循环。</span>
* 少部分情况需要循环一直执行,比如服务器的请求响应监听等。
* 循环条件一直为true就会造成无限循环(死循环),我们正常的业务编程中应该尽量避免死循环。会影响程序性能或者造成程序卡死奔溃!
### `do...while`循环
对于while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次。
`do...while `循环和`while` 循环相似,不同的是,`do...while`循环至少会执行一次。
```java
do{
//代码语句
}while(布尔表达式);
```
While和do-While的区别
* `while`先判断后执行。`do…while`是先执行后判断!
* `do...while`总是保证循环体会被至少执行一次!这是他们的主要差别。
### `for`循环
虽然所有循环结构都可以用 while或者do..while表示但Java 提供了另一种语句-`for`循环,使一些循环结构变得更加简单。
<span style="color:red">for循环语句是支持迭代的一种通用结构是最有效、最灵活的循环结构。</span>
for循环执行的次数是在执行前就确定的。语法格式如下
```java
for(初始化;布尔表达式;迭代){
//代码语句
}
```
> 关于for循环的几点说明
>
> 1. 最先执行初始化步骤。可以声明一种类型,可初始化一个或多个循环控制变量,也可以是空语句。
>
> 2. 然后检测布尔表达式的值。如果为true循环体被执行。如果为false循环终止开始执行循环体后面的语句。
>
> 3. 执行一次循环后,更新循环控制变量(送代因子控制循环变量的增减)。
>
> 4. 再次检测布尔表达式。循环执行上面的过程。
#### 增强型`for`循环
在java5中引入了一种主要用于数组或集合的增强型for循环。
```java
for(声明语句 : 表达式){
//代码
}
```
* **声明语句**:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
* **表达式**:表达式是要访问的数组名,或者是返回值为数组的方法。
```java
public class ForDemo {
public static void main(String[] args) {
int[] ary = {10,20,30,40,50}; //定义一个数组
//遍历数组中的元素
for(int x : ary){
System.out.println(x);
}
}
}
```
## 跳转语句
### break
在任何循环语句的主体部分均可用break控制循环的流程。break用于<span style="color:red">强行退出循环,不执行循环中剩余的语句。</span>(break语句也在switch语句中使用)
### continue
continue 语句用在循环语句体中,用于<span style="color:red">终止某次循环过程,即跳过循环体中尚未执行的语句,接着进行下一次是否执行循环的判定。</span>

View File

@ -0,0 +1,498 @@
---
title: Java语法基础
date: 2020-05-16 19:39:06
tags:
- Java
categories:
- Java基础
---
## 注释、标识符,关键字
### 注释
<!--more-->
平时我们编写代码,在代码量比较少的时候,我们还可以看懂自己写的,但是当项目结构一旦复杂起来,我们就需要用到注释了。
注释并不会被执行,是给写代码的人看的。
<span style = color:red>写注释是一个很好的习惯</span>
<span style = color:red>写代码要注意规范</span>
Java的注释有三种单行注释多行注释文档注释
```java
//单行注释
/*
多行注释
多行注释
*/
//JavaDoc:文档注释 /** */
//javadoc命令是用来生成自己API文档的
/**
* @author 作者名
* @version 版本号
* @since 指明需要最早使用的jdk版本
* @param 参数名
* @return 返回值情况
* @throws 异常抛出情况
*/
```
JavaDoc 可通过终端命令生成Api文档
```bash
javadoc -encoding UTF-8 -charset UTF-8 *.java
```
也可以通过Intellij IDEA生成在工具栏中找到 <u>T</u>ools------>Generate Java<u>D</u>oc…
![](https://i.loli.net/2020/05/15/5FeQRjBkPAirSKs.png)
### 关键字
![Java关键字](https://i.loli.net/2020/05/11/EjmKrwpXdu632gI.png)
### 标识符
<span style = color:red>Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。</span>
`标识符注意点:`
* 所有的标识符都应该以字母A-z或者a-z美元符$、或者下划线_开始
* 首字符之后可以是字母A-Z或者a-z美元符$、下划线_或数字的任何字符组合。
* <span style = color:red>不能使用关键字作为变量名或方法名。</span>
* 标识符是<span style = color:red>大小写敏感</span>
* <span style = color:red>可以使用中文命名但是一般不建议这样去使用也不建议使用拼音很Low不规范</span>
```java
//合法标识符举例age、$salary、value、_1_value
//非法标识符举例123abc、-salary、#abc
//中文命名举例
public static void mainstring[]args{
string 王者荣耀="最强王者";
System.out.println(王者荣耀);
}
```
## 数据类型
Java是强类型语言要求变量的使用要严格符合规定所有变量都必须先定义后才能使用。
![](https://i.loli.net/2020/05/11/NucZLt9mwnkRMyA.png)
```java
// 八大基本数据类型
//整数
int num1 = 10;
byte num2 = 20;
short num3 = 30;
long num3 = 30L; //long类型要在数字后加个 L
//小数:浮点数
float num5 = 50.1F; //float类型要在数字后加个 F
double num6 = 3.1415926535;
//字符型
char name1 = 'A'; //引号内只能有一个字符
//布尔值:只有是(true)、非(false) 两个值
boolean flag1 = true;
boolean flag2 = false;
```
> 位bit是计算机内部数据储存的最小单位11001100是一个八位二进制数。
>
> 字节byte是计算机中数据处理的基本单位习惯上用大写B来表示1Bbyte字节=8bit
>
> 字符:是指计算机中使用的字母、数字、字和符号
>
> 1bit表示1位1Byte表示一个字节1B=8b。1024B=1KB1024KB=1MB1024MB=1GB…
### 数据类型拓展
#### 整数拓展
进制问题:
二进制 0b十进制八进制 0十六进制 0x
```java
int i = 0b10; //二进制 输出2
int i1 = 10; //十进制 输出10
int i2 = 010; //八进制 输出8
int i3 = 0x10; //十六进制 输出16
```
#### 浮点数拓展
float和double类型表现的长度是有限的同时它也是离散的它存在`舍入误差`的问题,他的结果是一个大约数,接近但不等于。
<span style = color:red>尽量不要使用浮点数进行比较,尤其是在做涉及钱的业务时。</span>
看下面的例子:
```java
float f = 0.1f; //0.1
double d = 1.0/10; //0.1
System.out.println(f==d); //结果为false
float d1 = 2132154645646f;
float d2 = d1 + 1;
System.out.println(d1==d2); //结果为true
```
我们可以看出,浮点数是存在误差的。
Java中我们可以用`BigDecimal`这个数学工具类来执行上述的操作。
#### 字符拓展
所有字符本质还是数字
编码: Unicode码 u0000-uFFFF —>`UTF-8`UTF-16UTF-32
```java
//字符强制转换
char c1 = 'a';
char c2 = '中';
System.out.println(c1); //输出 a
System.out.println((int)c1); //强制转换 输出 97
System.out.println(c2); //输出 中
System.out.println((int)c2); //输出 20013
char c3 = '\u0061'; //十六进制
System.out.println(c3); //输出 a
```
转义字符
| 转义字符 | 作用 |
| :------: | :----------------------------------------------------------: |
| \n | 换行 |
| \t | 水平制表符 |
| \r | 回车,将当前位置移到本行开头 |
| \b | 退格,将当前位置移到前一列 |
| \f | 换页,将当前位置移到下页开头 |
| \\\ | 代表一个反斜线字符''\\' |
| \\' | 代表一个单引号(撇号)字符 |
| \\" | 代表一个双引号字符 |
| \0 | 空字符(NULL) |
| \ddd | 1到3位八进制数所代表的任意字符 \000 ~ \377 |
| \uxxxx | Unicode转义字符\u + 四个十六进制数字所代表的字符 \u0000 ~ \uFFFF |
#### 布尔值拓展
```java
boolean flag = true;
//下面的方式是同样的效果都表示当flag为真时做什么
if (flag == true) {}
if (flag){}
```
<span style = color:red>Less is More,代码要精简易读</span>
## 类型转换
由于Java是强类型语言所以要进行有些运算的时候需要用到类型转换。
```java
低--------------------------------------->高
byte,short,char->int->long->float->double
//浮点数优先级一定大于整数
```
运算中,不同类型的数据先转换为同一类型,然后进行运算。
```java
int i = 128;
//强制类型转换 (类型)变量名 高-->低
byte b =(byte)i; //byte类型范围为-128-127转换后内存溢出
//自动类型转换 低-->高
double d = i;
System.out.println(i); //输出 128
System.out.println(b); //输出 -128
System.out.println(d); //输出 128.0
System.out.println((int)23.7); //输出23
System.out.println((int)-45.54f); //输出 -45
```
<span style ="color:red"><b>注意:</b></span>
* 在类型转换时,要注意<span style="color:red">数据类型的取值范围,避免内存溢出</span>
* 不能对布尔值进行转换
* 不能把对象类型转换为不相干的类型
* 转换时还可能存在精度问题比如将浮点数转换为int类型会舍去小数部分。
**操作比较大的数的时候,注意溢出问题**
```java
//JDK7以后数字之间可以用下划线分割下划线并不会被打印出来
int money = 10_0000_0000;
int year = 20;
int total = money * year; //输出total的值为-1474836480。因为结果超出了int的范围溢出
long total2 = money * year;
//输出total2的值为-1474836480。因为运算顺序是先计算等式右边的再把结果转换为long类型赋值给total2但转换之前的结果已经出问题了。
long total3 = money*((long)year);
//这次total3的结果是正确的 先把一个数转换为long这样等式右边计算时就是以long类型在计算就不会发生溢出了
```
## 变量、常量、作用域
### 变量
变量就是可以变化的量!
Java是一种强类型语言每个变量都必须声明其类型。
Java变量是程序中最基本的存储单元其要素包括变量名变量类型和<span style ="color:red">作用域</span>
```java
type varNam [= value][{,varName[= value],...}];
//数据类型 变量名 = 值; 可以使用逗号隔开来声明多个同类型变量(不建议)。
```
<span style ="color:red">**注意:**</span>
* 每个变量都有类型,类型可以是基本类型,也可以是引用类型。
* 变量名必须是合法的标识符。
* 变量声明是一条完整的语句,因此每一个声明都必须以分号结束。
#### 类变量、实例变量、局部变量
```java
public class Variable{
static int allClicks = 0; //类变量
String str = "hello world"; //实例变量 从属于对象
public void method(){
int i = 0; //局部变量,必须声明和初始化值,作用域仅限这个方法之内
}
}
```
类变量:从属于类,作用域是在这个类内,随类一起出现,一起消失。
实例变量:从属于对象;如果不进行初始化,数值类型默认值为 0 | 0.0char类型默认为一个空格布尔类型默认值为false除了基本类型其余的默认都为 null。
局部变量,必须声明和初始化值,作用域仅限方法之内。
### 常量
常量(constant)<span style="color:red">初识化(initialize)后不能再改变值!</span>不会变动的值。
所谓常量可以理解成一种特殊的变量,它的值被设定后,在程序运行过程中不允许被改变。
常量名一般使用大写字符表示。
```java
final 常量名 = 值;
final double PI = 3.14;
```
> 说明:修饰符,不存在先后顺序, `final static double PI = 3.14`和`static final double PI = 3.14`是一样的。
### 变量的命名规范
* 所有变量、方法、类名:<span style="color:red">**见名知意**</span>
* 类成员变量首字母小写和驼峰原则monthSalary
* 局部变量:首字母小写和驼峰原则
* 常量大写字母和下划线MAX_VALUE
* 类名首字母大写和驼峰原则ManGoodMan
* 方法名首字母小写和驼峰原则run()runRun()
## 运算符
Java语言支持如下运算符
```java
算术运算符: +,-,*,/,%,++,--
赋值运算符: =
关系运算符: >,<,>=,<=,==,!=,instanceof
逻辑运算符: &&,||,!
位运算符: &,|,^,~,>>,<<,>>>
条件运算符: ? :
扩展赋值运算符:+=,-=,*=,/=
```
### 算数运算符
#### 基本运算符
```java
+(加),-(减),*(乘),/(除),%(模,取余)
```
```java
低--------------------------------------->高
byte,short,char->int->long->float->double
```
不同类型相互运算时结果的类型总是与要计算的数中优先级最高的那个数的类型保持一致但最低为int即当只有short、byte、char相互运算时结果仍为int类型。
```java
public class Test {
public static void main(String[] args) {
double a = 123.123;
float b = 123.123F;
long c = 123123123123123L;
int d = 123;
short e = 10;
byte f =8;
char g = 'a';
System.out.println(getType(a+b+c+d+e+f+g)); //double类型
System.out.println(getType(b+c+d+e+f+g)); //float类型
System.out.println(getType(c+d+e+f+g)); //long类型
System.out.println(getType(d+e+f+g)); //int
System.out.println(getType(e+f+g)); //int
System.out.println(getType(f+g)); //int
//获取变量类型的方法
private static String getType(Object o){
return o.getClass().toString();
}
}
```
#### 自增自减运算符
```java
// ++ -- 自增,自减 一元运算符
int a = 3;
int b = a++;//后置自增,执行这行代码时,先将a的值赋给b,a再自增
System.out.println(a); // 4
int c = ++a;//前置自增,执行这行代码时,先将a自增,再将自增后的结果赋给c
System.out.println(a); //5
System.out.println(b); //3
System.out.println(c); //5
```
### 关系运算符
关系运算符计算后返回的结果是`布尔值`,常与`if`判断语句结合使用。
### 逻辑运算符
```java
// &&(与),||(或),!(非)
//逻辑与运算两个变量都为真结果才为true
//逻辑或运算两个变量有一个为真则结果才为true
//非:如果是真则变为假,如果是假则变为真
boolean a = true;
boolean b = false;
System.out.println(a&&b); //false
System.out.println(a||b); //true
System.out.println(!(a&&b));//true
//短路运算
int c = 5;
boolean d = (c < 4)&&(c++ < 4); //如果&&前面的为false则后面的不会被运算
System.out.println(c); //5说明c++没有被运算
System.out.println(d); //false
```
### 位运算
```
A和B都是二进制数
A = 0011 1100
B = 0000 1101
A&B = 0000 1100 按位与都为1时为1其他情况为0
A|B = 0011 1101 按位或都为0时为0其他情况为1
A^B = 0011 0001 按位异或相同为0不同为1
~B = 1111 0010 按位取反
_________________________________________________
<<左移每移一位相当于乘以2
>>右移每移一位相当于除以2
如 2<<3 = 16
```
位运算由于是操作二进制数,所以效率极高。
### 扩展运算符
看下面例子
```java
a += b; //就相当于 a=a+b
a -= b; //就相当于 a=a-b
// 同样*=、/=也是这样的
```
### 条件运算符
```tex
条件运算符是三元运算符
x ? y : z
如果x为真则结果为有否则结果为z
```
### 运算符优先级
| 优先级 | 运算符 | 结合性 |
| ------ | -------------------------------------------------- | -------- |
| 1 | ()、[]、{} | 从左向右 |
| 2 | !、+、-、~、++、-- | 从右向左 |
| 3 | *、/、% | 从左向右 |
| 4 | +、- | 从左向右 |
| 5 | <<、>>、>>> | 从左向右 |
| 6 | <<=、>、>=、instanceof | 从左向右 |
| 7 | ==、!= | 从左向右 |
| 8 | & | 从左向右 |
| 9 | ^ | 从左向右 |
| 10 | \| | 从左向右 |
| 11 | && | 从左向右 |
| 12 | \|\| | 从左向右 |
| 13 | ? : | 从右向左 |
| 14 | =、+=、-=、*=、/=、&=、\|=、^=、~=、<<=、>>=、>>>= | 从右向左 |
### 拓展
1. 字符串连接符 +
```java
int a = 10;
int b = 20;
System.out.println("引号在前面"+a+b);// 输出 引号在前面1020
System.out.println(a+b+"引号在后面");// 输出 30引号在后面
```
可见,如果字符串在前面,则它后面连接的内容不会进行运算,如果字符串在后面,则它前面连接的内容会进行运算。
2. 很多运算,我们需要一些工具类来操作!如下代码用`Math`类进行幂运算。
```java
double power = Math.pow(2,3); //2的3次方8.0
```
## 包机制
为了更好地组织类Java提供了包机制用于区别类名的命名空间。
包语句的语法格式为:
```java
package pkg1[. pkg2[. pkg3...]];
```
<span style="color:red">一般利用公司域名倒置作为包名</span>
为了能够使用某一个包的成员我们需要在Java 程序中明确导入该包。使用`import`语句可完成此功能
```java
import package1[.package2...].(classname|*);
```

View File

@ -0,0 +1,331 @@
---
title: Java面向对象基础
date: 2020-09-30 12:17:29
tags:
- Java
- 面向对象
categories:
- Java基础
---
## 初识面向对象
### 面向过程和面向对象
**面向过程思想:**
* 是把模型分解成一步一步的过程。步骤清晰简单,第一步做什么,第二步做什么……
* 面向过程适合处理一些较为简单的问题
<!-- more -->
**面向对象思想:**
* 物以类聚,<span style="color:red">分类</span>的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
* 面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
<span style="color:red">对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路、来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。</span>
### 什么是面向对象
面向对象编程(Object-Oriented Progrsmming,OOP)是一种通过对象的方式,把现实世界映射到计算机模型的一种编程方法。
**面向对象编程的本质就是:**<span style="color:red">以类的方式组织代码,以对象的形式封装数据。</span>
**面向对象的核心思想:**
* **三大思想:**面向对象思想从概念上讲分为以下三种OOA、OOD、OOP
* OOA面向对象分析Object Oriented Analysis
* OOD面向对象设计Object Oriented Design
* OOP面向对象程序Object Oriented Programming
* **抽象**
* **三大特性**
* 封装性:所有的内容对外部不可见
* 继承性:将其他的功能继承下来继续发展
* 多态性:方法的重载本身就是一个多态性的体现
从认识论角度考虑是先有对象后有类。对象,是具体的事物。类,是抽象的,是对对象的抽象。
从代码运行角度考虑是先有类后有对象。类是对象的模板。
## 方法
具体可参考 [java方法](http://pengspace.top/2020/05/30/Java方法/#more),此处只做一些补充说明
#### 方法的定义
##### 修饰符
##### 返回类型
##### break和return的区别
`break`:结束整个循环
`continue`:结束本次循环
`return`: 结束方法,返回一个结果
##### 方法名
注意规范,首字母小写和驼峰原则。见名知意
##### 参数列表
(参数类型,参数名)…
##### 异常抛出
```java
修饰符 返回值类型 方法名(参数类型 参数名) throws 异常类型(如 IOException) {
...
方法体
...
return 返回值;
}
```
#### 方法的调用
##### 静态方法和非静态方法
<span style="color:red">非静态方法不能通过类名直接调用,若要调用非静态方法,必须先实例化该方法所在类的对象,通过对象来调用。</span>
<span style="color:red">静态方法可以通过类名直接调用,也可以通过对象调用。</span>
```java
//Demo.java
public class Demo {
public static void main(String[] args) {
Student.say1();
//Student.say2(); 错误,非静态方法不能通过类名直接调用
Student stu = new Student(); //实例化对象
stu.say1();
stu.say2();
}
}
//Student.java
public class Student {
//静态方法
public static void say1(){
System.out.println("静态方法");
}
//非静态方法
public void say2(){
System.out.println("非静态方法");
}
}
```
<span style="color:red">静态方法是和类一起加载的,而非静态方法是在类实例化后才会起作用的</span>,所以在类中,也不能在静态方法中去调用非静态方法
##### 形参与实参
> 形式参数:是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数。
>
> 实际参数:在调用有参函数时,主调函数和被调函数有数据传递关系。在主调函数中调用一个函数时,函数后面括号中的参数称为“实际参数”。
```java
public class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
//实际参数和形式参数的类型要对应
int add = demo.add(1,2); //1和2是实参
}
public int add(int a,int b){ //a和b是形参
return a+b;
}
}
```
实际参数是调用有参方法时真正传递的内容,而形式参数是用于接收实参内容的参数。
##### 值传递与引用传递
<span style="color:red">Java中都是值传递。</span>
后续会专门写一篇来讲述Java为什么都是值传递。
## 类与对象
### 类与对象的关系
<span style="color:red">类是一种抽象的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物。</span>比如Person类、Pet类、Car类等这些类都是<span style="color:red">用来描述/定义某一类具体事物应该具备的特点和行为。</span>
<span style="color:red">对象是抽象概念的具体实例。</span>比如 你就是个人的具体实例,你家的旺财就是狗的一个具体实例。<span style="color:red">能够体现出特点、展现出功能的是具体的实例,而不是一个抽象的概念。</span>
### 类的定义格式
```java
class 类名称{
成员属性
成员方法
}
属性定义格式:
数据类型 属性名;
属性定义并赋值的格式:
数据类型 属性名 = 初始化值;
方法定义格式:
权限修饰符 返回值类型 方法名(形式参数列表){
//方法体
return 返回值;
}
```
### 对象的创建
使用`new`关键字创建对象。
使用`new`关键字创建对象的时候,除了为对象分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中构造器的调用。
```java
一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:
类名称 对象名称 = new 类名称();
如果要想访问类中的属性或方法(方法的定义),则可以依靠以下的语法形式:
访问类中的属性: 对象.属性 ;
调用类中的方法: 对象.方法(实际参数列表) ;
```
### 构造方法(构造器)详解
一个类中即使什么都不写,也可以实例化该类的对象,那是因为,类中默认存在一个方法,就是<span style="color:red">**构造器**</span>
类中的<span style="color:red">**构造器**</span>也称为构造方法,是在进行创建对象的时候必须要调用的。并且构造器有以下两个特点:
* 必须和类的名字相同
* 必须没有返回类型也不能写void
我们在使用`new`关键字实例化对象时,本质是在调用构造器,来初始化值。
构造器可以重载,但注意,<span style="color:red">一旦你定义了有参构造器,如果还想使用无参构造,无参构造器就必须也显式定义。</span>
```java
//Person.java
public class Person {
//一个类即使什么都不写,它也会存在一个方法
//默认构造器 public Person(){}
String name;
//无参构造器
public Person(){
}
//有参构造器:一旦定义了有参构造,无参构造器就必须显式定义
public Person(String name){
this.name = name;
}
}
//Application.java
public class Application {
public static void main(String[] args) {
//new 实例化对象
Person person = new Person();
Person person1 = new Person("brian");
System.out.println(person.name); //null
System.out.println(person1.name); //brian
}
}
```
### 匿名对象
```tex
没有对象名称的对象 就是匿名对象。
匿名对象只能使用一次因为没有任何的对象引用所以将称为垃圾等待被GC回收。
只使用一次的对象可以通过匿名对象的方式完成,这一点在以后的开发中将经常使用到。
```
```java
public class Application {
public static void main(String[] args) {
int num = new Math().sum(100,20); //匿名对象
}
}
class Math {
int sum(int x,int y){
return x+y;
}
}
```
## 创建对象内存分析
### 栈
> Java栈的区域很小 , 大概2m左右 , 特点是存取的速度特别快
>
> 栈存储的特点是, 先进后出
>
> 存储速度快的原因:
>
> 栈内存, 通过 '栈指针' 来创建空间与释放空间 !
>
> 指针向下移动, 会创建新的内存, 向上移动, 会释放这些内存 !
>
> 这种方式速度特别快 , 仅次于PC寄存器 !
>
> 但是这种移动的方式, 必须要明确移动的大小与范围 , 明确大小与范围是为了方便指针的移动 , 这是一个对于数据存储的限制, 存储的数据大小是固定的 , 影响了程序 的灵活性 ~
>
> 所以我们把更大部分的数据 存储到了堆内存中
>
>
>
> 存储的是:
>
> 基本数据类型的数据 以及 引用数据类型的引用!
>
> 例如:
>
> int a =10;
>
> Person p = new Person();
>
> 10存储在栈内存中 , 第二句代码创建的对象的引用(p)存在栈内存中
### 堆
> 存放的是类的对象 .
>
> Java是一个纯面向对象语言, 限制了对象的创建方式:
>
> <span style="color:red">所有类的对象都是通过new关键字创建 </span>
>
> new关键字, 是指告诉JVM , 需要明确的去创建一个新的对象 , 去开辟一块新的堆内存空间:
>
> 堆内存与栈内存不同, 优点在于我们创建对象时 , 不必关注堆内存中需要开辟多少存储空间 , 也不需要关注内存占用 时长 !
>
> 堆内存中内存的释放是由GC(垃圾回收器)完成的
>
> 垃圾回收器 回收堆内存的规则:
>
> 当栈内存中不存在此对象的引用时,则视其为垃圾 , 等待垃圾回收器回收 !
### 方法区
> 存放的是
>
> - 类信息
> - 静态的变量
> - 常量
> - 成员方法
>
> 方法区中包含了一个特殊的区域 ( 常量池 )(存储的是使用static修饰的成员)
### PC寄存器
> PC寄存器保存的是 当前正在执行的 JVM指令的 地址 !
>
> 在Java程序中, 每个线程启动时, 都会创建一个PC寄存器 !
### 本地方法栈
> 保存本地(native)方法的地址 !

View File

@ -0,0 +1,569 @@
---
title: Java面向对象进阶
date: 2020-10-04 14:12:29
tags:
- Java
- 面向对象
categories:
- Java基础
---
> **static关键字**
>
> static表示“静态”的意思可以用来修饰成员变量和成员方法。
>
> static的主要作用在于创建独立于具体对象的域变量或者方法
>
> <!-- more -->
>
> 简单理解:
>
> 被static关键字修饰的方法或者变量不需要依赖于对象来进行访问只要类被加载了就可以通过类名去进行访问。 并且不会因为对象的多次创建而在内存中建立多份数据
>
> **注意**
>
> 1. <span style="color:red">静态成员在类加载时加载并初始化。</span>
> 2. <span style="color:red">无论一个类存在多少个对象 , 静态的属性, 永远在内存中只有一份(可以理解为所有对象公用 ) </span>
> 3. <span style="color:red">在访问时:静态不能访问非静态 , 非静态可以访问静态 ! 静态资源的执行时机可能早于非静态资源,一定不会晚于非静态资源</span>
> **final关键字**
>
> final表示“最终”的意思可以用来修饰属性、变量、类和方法
>
> final修饰的属性、变量就成为了常量无法对其再次进行赋值。final 修饰的局部变量只能赋值一次可以先声明后赋值final修饰的成员属性必须在声明时赋值
>
> 全局常量:`public static final 数据类型 变量名`
>
> final修饰的类不可以被继承
>
> final修饰的方法不能被子类重写
> **代码块**
>
> ```
> 普通代码块
> 在执行的流程中出现的代码块,我们称其为普通代码块。
> 构造代码块
> 在类中的成员代码块,我们称其为构造代码块,在每次对象创建时执行,执行在构造方法之前。
> 静态代码块
> 在类中使用static修饰的成员代码块我们称其为静态代码块在类加载时执行。 每次程序启动到关闭,只会执行一次的代码块。
> 同步代码块
> 在后续多线程技术中学习。
>
> 面试题:
> 构造方法与构造代码块以及静态代码块的执行顺序:
> 静态代码块 --> 构造代码块 --> 构造方法
> ```
>
>
> **mian()方法详解**
>
> `public static void main(String args[])`
>
> 以上的各个参数的含义如下:
>
> public表示公共的内容可以被所有操作所调用
>
> static表示方法是静态的可以由类名称直接调用。
>
> void表示没有任何的返回值操作
>
> main系统规定好的方法名称。如果main写错了或没有会报错NoSuchMethodError: main
>
> String[] args字符串数组接收参数的
## 面向对象的三大特征(抽象)
### 封装
该露的露,该藏的藏。我们程序设计要追求<span style="color:red">“高内聚,低耦合”</span>。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉,低耦合就是仅暴漏少量的方法给外部使用。
封装(数据的隐藏)。通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称之为信息隐藏。
总之就是:<span style="color:red">**属性私有get/set**</span>
```java
//Student.java
public class Student {
//属性:私有 private
private String name;//名字
private int idNum;//学号
private char sex;//性别
//提供一些可以操纵私有属性的方法
//set 设置值
public void setName(String name){
this.name = name; //this关键字this指当前对象
}
//get 获取值
public String getName(){
return this.name;
}
public void setIdNum(int id){
this.idNum = id;
}
public int getIdNum(){
return this.idNum;
}
public void setSex(char sex){
this.sex = sex;
}
public char getSex(){
return this.sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if(age>120 || age < 0){
this.age = 3;
}else {
this.age = age;
}
}
}
//Application.java
public class Application {
public static void main(String[] args) {
Student stu1 = new Student();
stu1.setName("brian");
System.out.println(stu1.getName());
stu1.setAge(20);
System.out.println(stu1.getAge());
}
}
```
> Idea快捷方式 <kbd>Alt</kbd>+<kbd>Insert</kbd> : 自动生成get/set方法
> 在Java基础中this关键字是一个最重要的概念。使用this关键字可以完成以下的操作
>
> * 调用类中的属性
> * 调用类中的方法或构造方法
> * 表示当前对象
> **权限修饰符**
>
> | 修饰符 | 类 | 包 | 子类 | 其他包 |
> | --------- | ---- | ---- | ---- | ------ |
> | public | √ | √ | √ | √ |
> | protected | √ | √ | √ | × |
> | default | √ | √ | × | × |
> | private | √ | × | × | × |
>
> 如上表所示public修饰的资源可以被其所在类所在包所在类的子类和其他包访问protecte修饰的资源不可以被其他包访问default修饰的资源只能被其所在类所在包访问而private修饰的资源只能被其所在类访问
### 继承
继承的本质是对某一批类的抽象,从而实现对现实世界更好的建模。
<span style="color:red">Java中类只有单继承多重继承没有多继承</span>
继承关系的两个类一个为子类派生类一个为父类基类。子类继承父类使用关键字extends来表示。
private 类型的属性和方法不可被继承,也就是说子类不能调用父类私有的属性和方法。
**object**类在Java类所有的类都默认直接或者间接继承Object类
**super**类似this,this指示的是当前对象super指示的是其父类对象。通过supe可以访问父类的构造方法、父类的属性和父类的方法。<span style="color:red">使用super调用了父类构造方法时必须要在子类构造器的第一行</span>
在我们创建子类对象时内存中会先创建父类对象再创建子类对象子类会通过super关键字拥有父类的地址来调用父类中可使用的属性和方法。
```java
//Person.java
package top.oop.demo05;
//父类
public class Person {
protected String name = "Brian";
public Person() {
System.out.println("Person父类的无参构造执行了");
}
public void print(){
System.out.println("Person");
}
}
//Student.java
package top.oop.demo05;
//子类
public class Student extends Person{
public Student() {
//隐藏代码调用了父类的无参构造。若要写必须要在子类构造器的第一行。如果父类没有无参构造则super(参数...)不可被省略。
super();
System.out.println("Student子类的无参构造执行了");
//super(); 错误。
}
private String name = "ZhangSan";
public void test(String name){
System.out.println(name);
System.out.println(this.name);//ZhangSan
System.out.println(super.name);//Brian
}
public void print(){
System.out.println("Student");
}
public void test1(){
print();
this.print();
super.print();
}
}
//Application.java
package top.oop;
import top.oop.demo05.Student;
public class Application {
public static void main(String[] args) {
Student stu = new Student();
/*
*结果:
Person父类的无参构造执行了
Student子类的无参构造执行了
*/
stu.test("张三");
/*
*结果:
张三
ZhangSan
Brian
*/
stu.test1();
/*
*结果:
Student
Student
Person
*/
}
}
```
> <span style="color:red">注意:</span>
>
> 1. super调用父类的构造方法必须在子类构造方法的第一个
> 2. super必须只能出现在子类的方法或者构造方法中
> 3. super和this不能同时调用构造方法
>
> super VS this
>
> * 代表的对象不同:
> * this : 本身调用者这个对象
> * super : 代表父类对象的应用
> * 前提:
> * this 没有继承也可以使用
> * super : 只能在继承条件下才能使用
> * 构造方法:
> * this() : 本类的构造
> * super() : 父类的构造
#### 方法重写:
规则:
- **参数列表必须完全与被重写方法的相同。**
- 一般情况下,**返回值类型必须完全与被重写方法的返回值类型相同**;当返回值为**类类型**时,重写的方法返回值可以不同,但**必须是父类方法返回值的子类**。
- **访问权限不能比父类中被重写的方法的访问权限更低**。例如:如果父类的一个方法被声明为 public那么在子类中重写该方法就不能声明为 protected。
- 父类的成员方法只能被它的子类重写。
- 声明为 final 的方法不能被重写。
- 声明为 static 和 private 的方法不能被重写,但是能够被再次声明。
- 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
- 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
- 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常。
- 构造方法不能被重写。
- 如果不能继承一个方法,则不能重写这个方法。
```java
//B.java
package top.oop.demo05;
public class B {
public void test(){
System.out.println("B->test()");
}
}
//A.java
package top.oop.demo05;
public class A extends B{
@Override //重写
public void test() {
System.out.println("A->test()");
}
}
//Application.java
package top.oop;
import top.oop.demo05.A;
import top.oop.demo05.B;
public class Application {
//静态方法:方法的调用只和左边定义的数据类型有关
//非静态方法:重写
public static void main(String[] args) {
A a = new A();
a.test(); //结果A->test()
//父类的引用指向子类
B b = new A();
b.test(); //子类重写了父类的方法 结果A->test()
}
}
```
> **为什么需要重写?**
>
> 1. 父类的功能,子类不一定需要,或者不一定满足。
> Idea快捷方式 <kbd>Ctrl</kbd>+<kbd>H</kbd> : 显示继承关系
> **重写override与重载overload的区别**
>
> 1. 重载发生在一个类中,重写发生在子父类中
> 2. 重载参数列表必须不同,重写的参数列表必须相同
> 3. 重载与返回值类型无关,重写的返回值类型必须一致或是父类的子类
> 4. 重载与访问权限无关,重写中,子类的方法的访问权限不能小于父类中被重写方法的权限
> 5. 重载与异常无关,重写的方法不能抛出新的异常,或者比被重写方法声明的更广泛的异常
### 多态
多态即同一方法可以根据发送对象的不同而采用多种不同的行为方式。一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多
多态存在的条件:
* 有继承关系
* 子类重写父类方法
* 父类引用指向子类对象 `Father f1 = new Son();`
> **注意:**
>
> 1. 多态是方法的多态,属性没有多态性
> 2. 父类和子类,有联系,若无,则会报异常(类型转换异常:ClassCastException)
> 有些方法无法重写:
>
> 1. static 方法 属于类,不属于实例对象
> 2. final
> 3. private 方法
```java
//Person.java 父类
package top.oop.demo06;
public class Person {
public void run() {
System.out.println("run");
}
}
//Student.java 子类
package top.oop.demo06;
public class Student extends Person{
@Override
public void run() {
System.out.println("son");
}
public void eat() {
System.out.println("eat");
}
}
//Application.java 测试类
package top.oop;
import top.oop.demo06.Person;
import top.oop.demo06.Student;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型是确定的,可以指向的引用类型就不确定了
// Person 父类,可以指向子类,但不能调用子类独有的方法
Person p1 = new Person(); //Person对象
Person s2 = new Student(); //Student对象 父类的引用指向子类
// Student 能调用的方法都是自己的或者继承父类的!
Student s1 = new Student(); //Student对象
p1.run(); //run 执行Person类的方法
s2.run(); //son 子类重写了父类的方法执行子类Student类的方法
s1.run(); //son
//s2.eat(); 错误:s2的引用类型为Person类型 它不能调用子类独有的方法
s1.eat(); //eat 执行Student类的方法
}
}
```
> **扩展: `instanceof`和类型转换**
>
> **`instanceof`**
>
> 关键字 `instanceof` Java 的一个二元操作符,类似于 ==>< 等操作符
>
> 它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
>
> ```java
> boolean result = obj instanceof Class
> ```
>
> 其中 obj 为一个对象Class 表示一个类或者一个接口,当 obj 为 Class 的对象或者是其直接或间接子类或者是其接口的实现类结果result 都返回 true否则返回false。
>
> 注意:编译器会检查 obj 是否能转换成右边的class类型如果不能转换则直接报错如果不能确定类型则通过编译具体看运行时定。
>
> **1. obj必须为引用类型不能是基本类型**
>
> ```java
> int i = 0;
> System.out.println(i instanceof Integer);//编译不通过
> System.out.println(i instanceof Object);//编译不通过
> ```
>
> instanceof运算符只能用作对象的判断。
>
> **2. obj 为 null**
>
> ```java
> System.out.println(null instanceof Object);//false
> ```
>
> 关于 null 类型的描述在官方文档https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.1 有一些介绍。一般我们知道Java分为两种数据类型一种是基本数据类型有八个分别是 byte short int long float double char boolean,一种是引用类型包括类、接口、数组等等。而Java中还有一种特殊的 null 类型,该类型没有名字,所以不可能声明为 null 类型的变量或者转换为 null 类型null 引用是 null 类型表达式唯一可能的值null 引用也可以转换为任意引用类型。我们不需要对 null 类型有多深刻的了解,我们只需要知道 null 是可以成为任意引用类型的**特殊符号**。
>
> 在 [JavaSE规范](https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.20.2) 中对 instanceof 运算符的规定就是:如果 obj 为 null那么将返回 false。
>
> **3. obj为class类的实例对象**
>
> ```java
> Integer integer = new Integer(1);
> System.out.println(integer instanceof Integer);//true
> ```
>
> **4. obj为class接口的实现类**
>
> 集合中有个上层接口 List其有个典型实现类 ArrayList
>
> ```java
> public class ArrayList<E> extends AbstractList<E>
> implements List<E>,RandomAccess,Cloneable,java.io.Serializable
> ```
>
> 所以我们可以用 instanceof 运算符判断 某个对象是否是 List 接口的实现类,如果是返回 true否则返回 false
>
> ```java
> ArrayList arrayList = new ArrayList();
> System.out.println(arrayList instanceof List);//true
> ```
>
> 或者反过来也是返回 true
>
> ```java
> List list = new ArrayList();
> System.out.println(list instanceof ArrayList);//true
> ```
>
> **5. obj为class类的直接或间接子类**
>
> 新建一个父类 Person然后在创建它的一个子类 Man
>
> ```java
> public class Person{
>
> }
> ```
>
> ```java
> public class Man extends Person{
>
> }
> ```
>
> 测试:
>
> ```java
> Person p1 = new Person();
> Person p2 = new Man();
> Man m1 = new Man();
> System.out.println(p1 instanceof Man);//false
> System.out.println(p2 instanceof Man);//true
> System.out.println(m1 instanceof Man);//true
> ```
>
> 注意第一种情况, `p1 instanceof Man` Man 是 Person 的子类Person 不是 Man 的子类,所以返回结果为 false。
>
> ###### 引用类型转换
>
> java的引用类型转换分为两种
>
> 1. 向上类型转换,是小类型到大类型的转换 ,子类转换为父类,可能会丢失自己本来的一些方法
>
> 2. 向下类型转换,是大类型到小类型的转换 (强制转换) 父类转化为子类
>
> **引用类型的强转条件** : 把父类类型(直接父类+间接父类) ---> 子类类型
>
> A x = (A)B; 只要B是A的父类,此句代码编译通过
>
> **强转的意义**:把父类类型强转为子类类型,在编译期可以调用子类的字段与方法(父类的字段与方法子类都能直接继承,但是子类有的父类有可能没有)==>强转之后,父类与子类的字段与方法都可以使用
>
> 现存在一个Person类Student子类和Teacher子类继承于Person父类
>
> ```java
> public class Person {
> public void run() {
> System.out.println("father class:run");
> }
> }
> public class Student extends Person {
> public void go() {
> System.out.println("son Student class:go");
> }
> }
> public class Teacher extends Person {
>
> }
> ```
>
> 实例化一个student对象如下
>
> ```java
> Student s = new Student(); //使用子类引用实例化子类对象
> //Teacher t = (Teacher)s; //不能转因为Student 与 Teacher没有继承关系
> Person p = s; //此时为向上引用转换,小类型转换为大类型,自动转换,并没有风险
> //p.go(); //错误Person引用类型不能调用子类独有的方法
> Person ps = new Person();
> //Student s2 = (Student)ps; //引用类型的大转小,强制转换.
> ```
>
> 向下引用转换应该先判断类型是否一致利用java的instanceof关键字判断。instanceof运算符用法判断是一个实例对象是否属于一个类是返回true否则返回false。
>
> ```java
> Person p2 = new Student();
> if(p2 instanceof Teacher) { //判断p2是否是Teacher类型的对象
> Teacher tea = (Teacher)p2;
> }else if(p2 instanceof Student) { //判断p2是否是Student类型的对象
> Student stu = (Student)p2;
> }
> /*
> 在实际项目中,p2的值可能是new Student()|new Teacher()|new Person(). 如果值是new Teacher()则把该对象p2强转为Teacher类型
> 问题如何判断p2的值到底是new的哪个类对象
> 方案使用instanceof. instanceof:判断指定变量是否是指定类型的对象。
> 当前场景:判断 p2 是否是 Teacher类型 的对象。
> 语法:指定变量 instanceof 指定类型。 返回false:不是指定类型的对象 反之则反
> 在运行期有效。
> */
> ```
>
> 但是当子类实例对象统一放进父类引用对象数组时,若要使用子类中的方法,必须先向下转换类型为子类引用,不然编译器会报错
>
> ```java
> Person[] people = {
> new Student(),
> new Teacher()
> };
> //people[0].go(); //报错
> if(people[0] instanceof Student) {
> ((Student)people[0]).go(); //son Student class:go
> }
> ```

View File

@ -0,0 +1,671 @@
---
title: Java面向对象高级
date: 2020-10-06 14:51:51
tags:
- Java
- 面向对象
categories:
- Java基础
---
## 抽象类
### 概念
有时候我们需要这样一个类,它不需要被实例化,也不需要实现完整的方法,它只是用来被继承的,用来限制子类的一个“规范”。这样的类我们就可以将它定义为**抽象类**,抽象类内的方法可以定义为**抽象方法**。
<!--more-->
```java
抽象类必须使用abstract class声明
一个抽象类中可以没有抽象方法。抽象方法必须写在抽象类或者接口中
只声明而未实现的方法称为抽象方法(未实现是指:没有“{}“方法体抽象方法必须使用abstract关键字声明。
格式:
abstract class 类名{ //抽象类
public abstract 返回值类型 方法名(); //抽象方法,只声明而未实现
}
```
> **注意:**
>
> 在抽象类的使用中有几个原则:
>
> * 抽象类本身是不能直接进行实例化操作的不能直接使用关键字new完成。
> * 一个抽象类必须被子类所继承,被继承的子类(如果不是抽象类)则**必须覆写(重写)**抽象类中的全部抽象方法。
>
> 常见的问题:
>
> * 抽象类不能使用final声明因为final修饰的类是不能有子类的 ,而抽象类必须有子类才有意义。
> * 抽象类能有构造方法,而且子类对象实例化的时候的流程与普通类的继承是一样的,都是要先调用父类中的构造方法(默 认是无参的),之后再调用子类自己的构造方法。
### 抽象类与普通类的区别
1. 抽象类必须用public或protected修饰(如果为private修饰那么子类则无法继承也就无法实现其抽象方法。默认缺省为 public
2. 抽象类不可以使用new关键字创建对象但是在子类创建对象时抽象父类也会被JVM实例化。
3. 如果一个子类继承抽象类那么必须实现其所有的抽象方法。如果有未实现的抽象方法那么子类也必须定义为abstract类
```java
//Person.java 抽象类
public abstract class Person {
public Person(){ //抽象类可以有构造方法
System.out.println("抽象类的构造方法执行了");
}
public abstract void run(); //抽象方法
}
//Student.java 子类
class Student extends Person {
@Override
public void run() {
System.out.println("Student.run");
}
}
//Application.java 测试类
public class Application {
public static void main(String[] args) {
//可以定义Person对象变量但它只能引用非抽象子类的对象
Person p = new Student(); //Student对象 父类的引用指向子类
p.run();
}
}
```
```tex
以上代码的运行结果为:
抽象类的构造方法执行了
Student.run
说明抽象类可以有构造方法在new一个抽象类的非子类对象时JVM会默认先执行抽象
类的构造方法。虽然我们不能new抽象类对象但我们可以通过子类来操作抽象类中的资源。
```
## 接口
### 接口的概念及定义
如果一个类中的全部方法都是抽象方法,全部属性都是全局常量,那么此时就可以将这个类定义成一个接 口。 定义格式:
```java
interface 接口名称{
全局常量 ;
抽象方法 ;
}
```
> **面向接口编程思想**
>
> 接口是定义(规范,约束)与实现(名实分离的原则)的分离的思想。
>
> 优点:
>
> 1. 降低程序的耦合性
> 2. 易于程序的扩展
> 3. 有利于程序的维护
```java
因为接口本身都是由全局常量和抽象方法组成,所以接口中的成员定义可以简写:
1.全局常量编写时,可以省略 public static final 关键字,例如:
public static final String INFO = "内容" ;
简写后:
String INFO = "内容" ;
2.抽象方法编写时,可以省略 public abstract 关键字,例如:
public abstract void print() ;
简写后:
void print() ;
```
### 接口的实现 implements
接口可以多实现,格式:
```java
class 子类 implements 父接口1,父接口2...{
}
```
以上的代码称为接口的实现。那么如果一个类即要实现接口,又要继承抽象类的话,则按照以下的格式编写 即可:
```java
class 子类 extends 父类 implements 父接口1,父接口2...{
}
```
> <span style="color:red">如果一个接口要想使用,必须依靠子类。 子类(如果不是抽象类的话)要实现接口中的所有抽象方法。</span>
```java
//Person.java 接口
public interface Person {
//int AGE = 10; //简写全局常量
void say(); //简写抽象方法
String getName();
}
//Student.java
public class Student implements Person{ //实现接口
private String name;
public Student(){}
public Student(String name){
this.name = name;
}
@Override
public void say() {
System.out.println(getName() + "say");
}
@Override
public String getName() {
return this.name;
}
}
//Application.java 测试类
public class Application {
public static void main(String[] args) {
Person p = new Student(); //Student对象 父类的引用指向子类
p.run();
}
}
```
### 接口的继承
接口因为都是抽象部分, 不存在具体的实现, 所以允许多继承,例如:
```java
interface C extends A,B{
}
```
继承相当于扩展了接口的方法
### default方法
JDK1.8之后规定在接口中可以定义default方法。例如把Person中的say()方法改为default方法
```java
//Person.java 接口
public interface Person {
String getName(); //简写抽象方法
default void say(){
System.out.println(getName() + "say");
}
}
//Student.java
public class Student implements Person{ //实现接口
private String name;
public Student(){}
public Student(String name){
this.name = name;
}
@Override
public String getName() {
return this.name;
}
}
//Application.java 测试类
public class Application {
public static void main(String[] args) {
Person p = new Student("Li Ming"); //Student对象 父类的引用指向子类
p.run();
}
}
```
实现类可以不必覆写default方法。default方法的目的是当我们需要给接口新增一个方法时会涉及到修改全部子类。如果新增的是default方法那么子类就不必全部修改只需要在需要覆写的地方去覆写新增方法。
### 接口与抽象类的区别
1. 抽象类要被子类继承,接口要被类实现。
2. 接口只能声明抽象方法,抽象类中可以声明抽象方法,也可以写非抽象方法。
3. 接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。
4. 抽象类使用继承来使用, 无法多继承。 接口使用实现来使用, 可以多实现
5. 抽象类中可以包含static方法 ,但是接口中不允许(静态方法不能被子类重写,因此接口中不能声明 静态方法)
6. 接口不能有构造方法,但是抽象类可以有
## Object 类
### 概念
Object类是所有类的父类基类如果一个类没有明确的继承某一个具体的类则将默认继承Object类。例如我们定义一个类
```java
public class Person{ }
```
其实它被使用时 是这样的:
```java
public class Person extends Object{ }
```
> **使用Object可以接收任意的引用数据类型**
### Object类中常用的方法
#### toString
建议重写Object中的toString方法。 此方法的作用:返回对象的字符串表示形式。
Object的toString方法 返回对象的内存地址
类`Object`的`toString`方法返回一个字符串,该字符串由对象为实例的类的名称,字符“ `@` ”以及对象的哈希码的无符号十六进制表示形式组成。 换句话说,此方法返回一个等于值的字符串:
```java
getClass().getName() + '@' + Integer.toHexString(hashCode())
```
```java
//Person.java
package top.oop.demo09;
public class Person {
private String name;
private int age;
private int id; //唯一标识符
public Person(String name, int age,int id) {
this.name = name;
this.age = age;
this.id = id;
}
public Person() {}
// getter和setter方法省略若想放入ide中测试请自行添加
}
//Application.java 测试类
package top.oop.demo09;
public class Application {
public static void main(String[] args) {
Person p = new Person("Li Ming",18);
System.out.println(p.toString()); //top.oop.demo09.Person@27f674d
}
}
```
可以看出如果不重写toString()那打印的结果明显不能体现出我们所创建的对象的特征。所以建议在类中去重写toString()方法。
我们可以在Person中重写toString()方法。
```java
@Override
public String toString(){
return ("这是一个人,他叫" + this.name + "," + this.age + "岁了");
}
```
#### equals
先来看一段代码
```java
//Person.java 看上面toString中的Person.java
//Application.java 测试类
package top.oop.demo09;
public class Application {
public static void main(String[] args) {
Person p1 = new Person("Li Ming",18);
Person p2 = new Person("Li Ming",18);
System.out.println(p1 == p2); //false
}
}
```
我们可以看出p1和p2的内容信息是完全一样的但我们用 `== `比较时会返回false。其实这也很好理解每当我们new一个对象时就会在内存中开辟一块空间也就是说p1和p2指向的是不同的内存地址程序当然会判定他们不等。
但我们总需要对对象的信息进行比较这时我们可以重写Object中的equals()方法来解决。不能直接用,直接用相当于还是在用`==` 比较。可以看Object中equals方法的源码如下:
```java
public boolean equals(Object obj) {
return (this == obj);
}
```
建议重写Object中的equals(Object obj)方法,此方法的作用:指示某个其他对象是否“等于”此对象。
Object的equals方法实现了对象上最具区别的可能等价关系; 也就是说,对于任何**非空引用**值x和y当且仅当 x和y引用同一对象 x == y具有值true 此方法返回true 。
> equals方法重写时的五个特性
>
> * 自反性 对于任何非空的参考值x x.equals(x)应该返回true 。
> * 对称性 对于任何非空引用值x和yx.equals(y)应该返回true当且仅当y.equals(x)回报true 。
> * 传递性 对于任何非空引用值x y和z 如果x.equals(y)返回true且y.equals(z)返回true ,那么 x.equals(z)应该返回true 。
> * 一致性 对于任何非空引用值x和y 多次调用x.equals(y)始终返回true或始终返回false 前提是未修改对象上的equals比较中使用的信息。
> * 非空性 对于任何非空的参考值x x.equals(null)应该返回false 。
equals一般根据我们的业务进行重写举个例子,我们可以在Person类中重写equals方法当唯一标识符id相等时我们就认为这两个对象相等
```java
@Override
public boolean equals(Object obj) {
if(this == obj) //如果传入的对象与当前对象内存地址一样,那一定是相同的
return true;
}
if(obj == null){ //如果传入的对象为空根据非空性返回false
return false;
}
if(o instanceof Person){ //如果传入的对象与当前对像类型相同
Person p2 = (Person)obj; //将obj对象强转为Person对象
if(this.id == p2.id){
return true;
}else{
return false;
}
}else{
return false;
}
}
```
以上代码可以进行简化,如下:
```java
@Override
public boolean equals(Object obj) {
//如果传入的对象与当前对象内存地址一样,那一定是相同的
if(this == obj){
return true;
}
//如果传入的对象为空或与当前对象类型不同返回false
if(obj == null || !(obj instanceof Person){
return false;
}
Person p = (Person)obj; //将obj对象强转为Person对象
return (this.id == p.id);
}
```
> IDEA 快捷键 `Alt+Inster `可以自动重写equals方法和toString方法
## 内部类
在Java中可以将一个类定义在另一个类里面或者一个方法里面这样的类称为内部类。
广泛意义上的内部类一般来说包括这四种:
1. 成员内部类
2. 局部内部类
3. 匿名内部类
4. 静态内部类
###成员内部类
**定义:**成员内部类是最普通的内部类,它的定义为位于另一个类的内部,形如下面的形式:
```java
class Outer {
private double x = 0;
public Outer(double x) {
this.x = x;
}
class Inner { //成员内部类
public void say() {
private double x = 200; //与外部类同名的变量
System.out.println("x="+ x); // x = 200.0
System.out.println("x=" + Outer.this.x); //访问外部类的同名成员
}
}
}
```
**特点:**
成员内部类可以无条件访问外部类的所有成员属性和成员方法包括private成员和静态成员。不过要注意的是当成员内部类拥有和外部类同名的成员变量或者方法时会发生隐藏现象即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员需要以下面的形式进行访问
```java
外部类.this.成员变量
外部类.this.成员方法
```
**成员内部类的使用:**
以上面定义的Outer类为例来看如何让使用它里面的内部类
```java
public class TestInner {
public static void main(String[] args) {
Outer outer = new Outer(100);
Outer.Inner inner = outer.new Inner();
inner.say();
/*结果:
* x = 200.0
* x = 100.0
*/
}
}
```
###局部内部类
局部内部类是**定义在一个方法或者一个作用域里面的类**,它和成员内部类的区别在于**局部内部类的访问仅限**
**于方法内或者该作用域内**。例如:
```java
class Person{
public Person() { }
}
class Man{
public Man(){ }
public People getPerson(){
class Student extends People{ //局部内部类 定义在了getPerson方法内
int age =0;
}
return new Student();
}
}
```
> **注意:**局部内部类就像是方法里面的一个局部变量一样是不能有public、protected、private以及
> static修饰符的。
下面我们使用系统的某个API来演示局部内部类的使用。
```java
import java.awt.Frame;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class LocalInnerClass {
public static void main(String[] args) {
Frame f = new Frame("登录"); //新建一个窗体
f.setVisible(true); //设置是否显示
f.setSize(300,200); //设置大小
class MyWindowListener implements WindowListener { //局部内部类
@Override
public void windowOpened(WindowEvent e) {
}
@Override
public void windowClosing(WindowEvent e) {
System.out.println("关闭窗口");
System.exit(0); //关闭窗口操作
}
@Override
public void windowClosed(WindowEvent e) {
}
@Override
public void windowIconified(WindowEvent e) {
}
@Override
public void windowDeiconified(WindowEvent e) {
}
@Override
public void windowActivated(WindowEvent e) {
}
@Override
public void windowDeactivated(WindowEvent e) {
}
}
MyWindowListener l = new MyWindowListener();
f.addWindowListener(l); //窗口监听器,需要传入一个实现WindowListener接口的类类型
}
}
```
### 匿名内部类
匿名内部类由于没有名字,只能使用一次。创建格式如下:
```java
new 父类构造器(参数列表)|实现接口()
{
//匿名内部类的类体部分
}
```
在这里我们看到使用匿名内部类我们必须要继承一个父类或者实现一个接口当然也仅能只继承一个父类或者实现一个接口。同时它也是没有class关键字这是因为匿名内部类是直接使用new来生成一个对象的引用。这个引用是隐式的。
> 在使用匿名内部类的过程中,我们需要注意如下几点:
>
> 1. 使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能
> 继承一个类或者实现一个接口。
> 2. 匿名内部类中是不能定义构造函数的。
> 3. 匿名内部类中不能存在任何的静态成员变量和静态方法。
> 4. **匿名内部类为局部内部类**,所以局部内部类的所有限制同样对匿名内部类生效。
> 5. 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
> 6. 和局部内部类一样只能访问final型的局部变量因为内部类会被单独编译成一个字节码文件为了保障这个单独的文件中用到的内部类外部的变量与内部类外部的变量的值绝对一致系统从规则上限制这个值不可以被更改。
```java
//Person接口
public interface Person {
void say();
}
//匿名内部类演示
public class NoNameInnerClass {
public static void main(String[] args) {
final int a = 10; //jdk1.8以后可以省略final
int b = 1;
b = 2; //明显b不是final型的
Person p = new Person() { //匿名内部类 实现了Person接口
@Override
public void say() {
System.out.println("匿名内部类中的say方法" + a);
//System.out.println(b); //报错局部内部类和匿名内部类不能访问非final型的局部变量
}
};
ha(p);
}
public static void ha(Person p){
}
}
```
### 静态内部类
静态内部类也是定义在另一个类里面的类只不过在类的前面多了一个关键字static。
静态内部类是不需要依赖于外部类对象的,这点和类的静态成员属性有点类似,并且它**不能使用外部类的非**
**static成员变量或者方法.**
```java
public class Test {
public static void main(String[] args) {
StaticInnerClass.y = 100;
Outter.Inner inner = new Outter.Inner();
inner.say(); //100.0
}
}
class Outter {
private double x = 0;
public static double y = 10;
public Outer(double x,double y) {
this.x = x;
}
class Inner { //成员内部类
public void say() {
//System.out.println(x); //报错,静态内部类不能访问外部类的非静态成员和方法
System.out.println(y);
}
}
}
```
## 包装类
在Java中有一个设计的原则“一切皆对象”那么这样一来Java中的一些基本的数据类型就完全不符合于这种设计思想因为Java中的八种基本数据类型并不是引用数据类型所以Java中为了解决这样的问题引入了八种基本数据类型的包装类。
| 基本数据类型 | 包装类 |
| ------------ | --------- |
| int | Integer |
| char | Character |
| float | Float |
| double | Double |
| boolean | Boolean |
| byte | Byte |
| short | Short |
| long | Long |
以上的八种包装类,可以将基本数据类型按照类的形式进行操作。
以上的八种包装类也分为两种大的类型:
* NumberInteger、Short、Long、Double、Float、Byte都是Number的子类表示是一个
数字。
* ObjectCharacter、Boolean都是Object的直接子类。
### 装箱和拆箱操作
以下以`Integer`和`Float`为例进行操作
将一个**基本数据类型变为包装类,那么这样的操作称为装箱操作**。
将一个**包装类变为一个基本数据类型,这样的操作称为拆箱操作**
因为所有的数值型的包装类都是Number的子类Number的类中定义了如下的操作方法以下的全部方法都
是进行拆箱的操作。
| 方法 | 描述 |
| ------------------------------------ | ------------------ |
| public byte byteValue() | 用于Byte->byte |
| public abstract double doubleValue() | 用于Double->double |
| public abstract float floatValue() | 用于Float->float |
| public abstract int intValue() | 用于Integer->int |
| public abstract long longValue() | 用于Long->long |
| public short shortValue() | 用于Short->short |
**装箱操作:**
在JDK1.4之前 ,如果要想装箱,直接使用各个包装类的构造方法即可,例如:
```java
int temp = 10 ; // 基本数据类型
Integer x = new Integer(temp) ; // 将基本数据类型变为包装类
```
在JDK1.5Java新增了自动装箱和自动拆箱而且可以直接通过包装类进行四则运算和自增自减操作。例
如:
```java
Float f = 10.3f ; // 自动装箱
float x = f ; // 自动拆箱
System.out.println(f * f) ; // 直接利用包装类完成
System.out.println(x * x) ; // 直接利用包装类完成
```
### 字符串转换
使用包装类还有一个很优秀的地方在于:可以将一个字符串变为指定的基本数据类型,此点一般在接收输入
数据上使用较多。
在`Integer`类中提供了以下的操作方法:
`public static int parseInt(String s)` 将String变为int型数据
在`Float`类中提供了以下的操作方法:
`public static float parseFloat(String s) `将String变为Float
在`Boolean` 类中提供了以下操作方法:
`public static boolean parseBoolean(String s) `将String变为boolean
……
```java
public class demo11 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String text = input.nextLine();
int x = Integer.parseInt(text); //转为int类型,便于运算
System.out.println(x+1);
}
}
```

View File

@ -0,0 +1,79 @@
---
title: MVC模式和三层架构
date: 2020-12-12 13:56:15
tags:
- JavaWeb
- MVC
- 三层架构
categories:
- JavaWeb
---
为了便于管理繁杂的代码以及降低代码的耦合性于是衍生出了MVC模式可以使开发者思路更加清晰且代码更加利于维护。
## MVC 模式
Web MVC中的M(模型)-V(视图)-C(控制器)概念和标准MVC概念一样Web MVC标准架构如下图所示
![image-20201126203504738](https://i.loli.net/2020/11/26/VAHzbtaiFC1yDc3.png)
<!--more-->
`M(Model) 模型` : 应用程序的核心功能,管理这个模块中用的数据和值,**包含Dao层和Bean层**
`V(View )视图`: 视图提供模型的展示,管理模型如何显示给用户,它是应用程序的外观,**一般指JSP或HTML前端页面**
`C(Controller)控制器`: 对用户的输入做出反应,管理用户和视图的交互,是连接模型和视图的枢纽。**包含Servlet层和Service层**
MVC用于将webUI层进行职责解耦
## 三层架构
通常意义上的三层架构就是将整个业务应用划分为:**表现层UI、业务逻辑层BLL、数据访问层DAL**。区分层次的目的即为了「高内聚,低耦合」的思想。
* 表现层UI通俗讲就是展现给用户的界面即用户在使用一个系统的时候他的所见所得。 jsp/html
* 业务逻辑层BLL针对具体问题的操作也可以说是对数据层的操作对数据业务逻辑处理。
servletservice
* 数据访问层DAL该层所做事务直接操作数据库针对数据的增添、删除、修改、更新、查找等。dao
> 表现层实现的代表作品是Strutsspringmvc框架
>
> 业务层实现的代表作品是Spring
>
> 持久层实现的代表作品是Hibernate,mybatis。
层就相当于一个黑盒子,我们不用知道它内部怎么实现,只需要知道如何去调用它就行了。每层只与上下相邻的两层打交道。当一层内部由于技术变迁发生变化时,只要接口不变,其他层不用做任何改变。分层之后灵活性提高,也便于团队分工开发。
## 三层架构和MVC的区别与联系
![](https://i.loli.net/2020/11/26/A95vVS3qPnzY82y.jpg)
MVC是 Model-View-Controller严格说这三个加起来以后才是三层架构中的UI层也就是说MVC把三层架构中的UI层再度进行了分化分成了控制器、视图、实体三个部分控制器完成页面逻辑通过实体来与界面层完成通话而C层直接与三层中的BLL进行对话。
MVC可以是三层中的一个表现层框架属于表现层。三层和mvc可以共存。
三层是基于业务逻辑来分的而MVC是基于页面来分的。
MVC主要用于表现层三层主要用于体系架构三层一般是表现层、中间层、数据层其中表现层又可以分成M、V、C(Model View Controller)模型-视图-控制器
MVC是表现模式Presentation Pattern三层架构是典型的架构模式Architecture Pattern
三层架构的分层模式是典型的上下关系上层依赖于下层。但MVC作为表现模式是不存在上下关系的而是相互协作关系。即使将MVC当作架构模式也不是分层模式。
MVC和三层架构基本没有可比性是应用于不同领域的技术。
> [https://www.cnblogs.com/zhhh/archive/2011/06/10/2077519.html](https://www.cnblogs.com/zhhh/archive/2011/06/10/2077519.html)这篇文章对MVC和三层的关系是这样说的
>
> **三层是三层MVC是MVC它们毫无关系的。**
>
> **三层**是从整个应用程序架构的角度来分的三层(如果程序需要,还可以分多层)。
>
> 三层是为了解决整个应用程序中各个业务操作过程中不同阶段的代码封装的问题,为了使程序员更加专注的处理某阶段的业务逻辑。
>
> 比如将数据库操作代码封装到一层中,提供一些方法根据参数直接返回用户需要的相应数据,这样在处理具体的业务逻辑的时候,就不用关心数据的存储问题了。
>
> **MVC**是在应用程序BS结构的视图层划分出来的不同功能的几个模块。
>
> MVC主要是为了解决应用程序用户界面的样式替换问题把展示数据的 HTML 页面尽可能的和业务代码分离。MVC把纯净的界面展示逻辑用户界面独立到一些文件中Views把一些和用户交互的程序逻辑Controller单独放在一些文件中在 Views 和 Controller 中传递数据使用一些专门封装数据的实体对象这些对象统称为Models。
>
> 之所以说MVC和三层毫无关系是因为它们二者使用范围不同三层可以应用于任何语言、任何技术的应用程序而MVC只是为了解决BS应用程序视图层各部分的耦合关系。它们互不冲突可以同时存在也可根据情况使用其中一种。

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,763 @@
---
title: MySQL数据库高级
date: 2020-11-16 19:41:42
tags:
- 数据库
- MySQL
categories:
- 数据库
---
## DQL数据查询进阶
这里所用到的表结构如下图所示:
![](https://i.loli.net/2020/11/11/T2PUqaGgcXIZv18.png)
<!-- more -->
### 子查询
子查询即嵌套在其他查询中的查询。可以利用嵌套关系完成一些复杂情况的查询。
> **例子 1利用子查询进行过滤**
>
> 订单存储在两个表中。对于包含订单号、客户ID、订单日期的每个订单orders表存储⼀行。 各订单的物品存储在相关的orderitems表中。orders表不存储客户信息。它只存储客户的ID。实际的客户信息存储在customers表中。现在假如需要列出订购了物品TNT2的所有客户可以用下面的方式查询
>
> ```mysql
> -- 从oderitems表中查询所有包含物品TNT2中的订单编号order_num;
> -- 将上一步查询出的order_num作为在oders表中查询的条件查询出符合条件的用户编号cust_id;
> -- 再将上一步查询出的cust_id作为在customers表中查询的条件,就可以查询出订购了物品TNT2的所有客户啦
> SELECT cust_name,cust_contact
> FROM customers
> WHERE cust_id IN (
> SELECT cust_id
> FROM orders
> WHERE order_num IN (
> SELECT order_numFROM orderitems WHERE prod_id = 'TNT2'
> )
> );
> -- 查询结果:
> +----------------+--------------+
> | cust_name | cust_contact |
> +----------------+--------------+
> | Coyote Inc. | Y Lee |
> | Yosemite Place | Y Sam |
> +----------------+--------------+
> ```
>
> **例子 2作为计算字段使用子查询**
>
> 假如需要显示customers表中每个客户的订单总数。订单与相应的客户ID存储在orders表中。
>
> ```mysql
> -- 从customers表中检索客户列表。对于检索出的每个客户统计其在orders表中的订单数目。
> SELECT cust_id,cust_name,
> (SELECT COUNT(*)
> FROM orders
> WHERE orders.cust_id = customers.cust_id) as ordersNum
> FROM customers
> ORDER BY cust_name;
>
> -- 查询结果
> +---------+----------------+-----------+
> | cust_id | cust_name | ordersNum |
> +---------+----------------+-----------+
> | 10001 | Coyote Inc. | 2 |
> | 10005 | E Fudd | 1 |
> | 10002 | Mouse House | 0 |
> | 10003 | Wascals | 1 |
> | 10004 | Yosemite Place | 1 |
> +---------+----------------+-----------+
> ```
>
> 这条SELECT 语句对customers 表中每个客户返回3 列cust_name、cust_state和ordersNum。ordersNum是一个计算字段它是由圆括号中的子查询`SELECT COUNT(*) FROM orders WHERE orders.cust_id = customers.cust_id) as ordersNum)`建立的。该子查询对检索出的每个客户执行一次。在此例子中该子查询执行了5次因为检索出了5个客户。
>
> > 子查询中的WHERE子句与前面使用的WHERE子句稍有不同因为它使用了完全限定列名。这种方式叫做相关子查询它是涉及外部查询的子查询。任何时候只要列名可能有多义性就必须使用这种语法。因为有两个cust_id列一个在customers中另一个在orders中需要⽐比较这两个列列以正确地把订单与它们相应的顾客匹配
> >
> > ```mysql
> > WHERE orders.cust_id = customers.cust_id
> > ```
### 联表查询
SQL最强大的功能之⼀就是能在数据检索查询的执行中联结join表。在能够有效地使⽤用联结前必须了了解关系表以及关系数据库设计的⼀些基础知识
#### 表关系
MySQL作为一个关系型数据最大的特点便是通过表与表之间的关系可以有效地存储和方便地处理数据
**关系表的设计就是要保证把信息分解成多个表,一类数据一个表。各表通过某些常用的值(即关系设计中的关系(relational))互相关联。**
表与表之间的关系,通过外键进行关联。**外键存在于两个拥有相同字段的表中,其中一个表的主键在另一个表中作为外键**查找数据时,可以通过外键确定数据对应关系。
表关系又下面三种
* 一对一关系就是在一个表A中的一条数据对应着另外一张表B中的一条数据反过来也是。
* 一对多多对一关系在一个表A中的一条数据对应着另外一个表B中的多条数据但反过来另一个表B中的一条数据也只能对应表A中的一条数据比如爸爸和儿女一个爸爸可以有很多儿女但一个儿女只能有一个爸爸。
* 多对多关系在一个表A中的一条数据对应另一个表B中的多条数据同时表B中的一条数据也对应着表A中的多条数据
![](https://i.loli.net/2020/11/11/ki3lRrb2MfgV7hX.png)
> 有关**表关系**更详细的内容可以看这两篇文章
>
> [https://cloud.tencent.com/developer/article/1585927](https://cloud.tencent.com/developer/article/1585927)
>
> [https://blog.csdn.net/weixin_40001125/article/details/88252494](https://blog.csdn.net/weixin_40001125/article/details/88252494)
#### 表联结查询
如果数据存储在多个表中怎样⽤用单条SELECT语句句检索出数据
答案是使⽤用联结。简单地说联结是⼀种机制用来在一条SELECT语句中关联表因此称之为联
结。
使⽤用特殊的语法,可以联结多个表返回一组输出,联结在运行时关联表中正确的行。
##### 内联结等值连接——INNER JOIN
获取两个表中字段匹配关系的记录。
```mysql
SELECT 表名1.字段名1,表名2.字段名2... FROM 表名1 INNER JOIN 表名2 ON 表名1.字段名3 = 表名2.字段名3;
```
也可以省略 INNER ,只写一个 JOIN。
![](https://i.loli.net/2020/11/11/B9bHELYmCAZwiJ1.png)
> 举例:我们需要查询出所有的商品及对应的供应商信息:
>
> ```mysql
> SELECT vend_name,prod_name,prod_price
> FROM vendors INNER JOIN products
> ON vendors.vend_id = products.vend_id
> -- 查询结果
> +-------------+----------------+------------+
> | vend_name | prod_name | prod_price |
> +-------------+----------------+------------+
> | ACME | Bird seed | 10.00 |
> | ACME | Carrots | 2.50 |
> | ACME | Detonator | 13.00 |
> | ACME | Safe | 50.00 |
> | ACME | Sling | 4.49 |
> | ACME | TNT (1 stick) | 2.50 |
> | ACME | TNT (5 sticks) | 10.00 |
> | Anvils R Us | .5 ton anvil | 5.99 |
> | Anvils R Us | 1 ton anvil | 9.99 |
> | Anvils R Us | 2 ton anvil | 14.99 |
> | Jet Set | JetPack 1000 | 35.00 |
> | Jet Set | JetPack 2000 | 55.00 |
> | LT Supplies | Fuses | 3.42 |
> | LT Supplies | Oil can | 8.99 |
> +-------------+----------------+------------+
> ```
>
> 上面语句等价于:
>
> ```mysql
> SELECT vend_name,prod_name,prod_price
> FROM vendors,products
> WHERE vendors.vend_id = products.vend_id
> ```
多表联结SQL对⼀一条SELECT语句句中可以联结的表的数目没有限制。
```mysql
SELECT 表名1.字段名1,表名2.字段名2...
FROM 表名1
INNER JOIN 表名2 ON 表名1.字段名3 = 表名2.字段名3
INNER JOIN 表名3 ON 表名2.字段名4 = 表名3.字段名4
...
(WHERE 过滤条件);
-- ON 后面跟联结条件
```
##### 自联结
自联结在查询一些特定数据时可以作为子嵌套查询的替代
这时候就需要自己与自己进行联结为了区分需要用AS取一个别名
> 举例:
>
> 假如你发现某物品其ID为DTNTR存在问题因此想知道生产该物品的供应商生产的其他物品是否也存在这些问题。此查询要求首先找到生产ID为DTNTR的物品的供应商然后找出这个供应商生产的其他物品。
>
> ```mysql
> -- 1.自联结 JOIN
> SELECT p1.prod_id,p1.prod_name
> FROM products AS p1
> JOIN products AS p2
> ON p1.vend_id = p2.vend_id
> WHERE p2.prod_id = 'DTNTR';
> -- 2.自联结 WHERE
> SELECT p1.prod_id,p1.prod_name
> FROM products AS p1,products AS p2
> WHERE p1.vend_id = p2.vend_id AND p2.prod_id = 'DTNTR';
> -- 3.子查询
> SELECT prod_id,prod_name
> FROM products
> WHERE vend_id = (SELECT vend_id FROM products WHERE prod_id = 'DTNTR');
> -- 查询结果
> +---------+----------------+
> | prod_id | prod_name |
> +---------+----------------+
> | DTNTR | Detonator |
> | FB | Bird seed |
> | FC | Carrots |
> | SAFE | Safe |
> | SLING | Sling |
> | TNT1 | TNT (1 stick) |
> | TNT2 | TNT (5 sticks) |
> +---------+----------------+
> ```
>
>
自联结通常作为外部语句用来替代从相同表中检索数据时使用的子查询语句。虽然最终的结果是相同的,但有时候**处理联结远比处理子查询快得多**。
##### 外部联结
* 左联结 LEFT JOIN以左侧表为基准去关联右侧的表进行联结如果有未关联的数据那么结果为null
* 右联结 RIGHT JOIN以右侧表为基准去关联左侧的表进行联结如果有未关联的数据那么结果为null
![](https://i.loli.net/2020/11/11/NszZBtwy3GSOMcU.png)
> 例如:我们要对每个客户下了多少订单进行计数,**包括那些至今尚未下订单的客户**
>
> ```mysql
> -- 1.内部联结。它检索所有客户及其订单:
> SELECT customers.cust_id,orders.order_num
> FROM customers INNER JOIN orders
> ONcustomers.cust_id = orders.cust_id;
> +---------+-----------+
> | cust_id | order_num |
> +---------+-----------+
> | 10001 | 20005 |
> | 10001 | 20009 |
> | 10003 | 20006 |
> | 10004 | 20007 |
> | 10005 | 20008 |
> +---------+-----------+
> -- 明显这种方式不能达到我们的要求,它不包含至今尚未下订单的客户 10002
>
> -- 2.外部联结。检索所有客户,包括那些没有订单的客户
> SELECT customers.cust_id,orders.order_num
> FROM customers LEFT JOIN orders
> ON customers.cust_id = orders.cust_id;
> -- 也可以写成这样
> SELECT customers.cust_id,orders.order_num
> FROM orders RIGHT JOIN customers
> ON customers.cust_id = orders.cust_id;
> -- 查询结果
> +---------+-----------+
> | cust_id | order_num |
> +---------+-----------+
> | 10001 | 20005 |
> | 10001 | 20009 |
> | 10002 | NULL |
> | 10003 | 20006 |
> | 10004 | 20007 |
> | 10005 | 20008 |
> +---------+-----------+
>
> -- 加入订单量计数
> SELECT customers.cust_id,customers.cust_name,COUNT(orders.order_num) AS num_ord
> FROM customers LEFT JOIN orders
> ON customers.cust_id = orders.cust_id
> GROUP BY customers.cust_id;
> -- 查询结果
> +---------+----------------+---------+
> | cust_id | cust_name | num_ord |
> +---------+----------------+---------+
> | 10001 | Coyote Inc. | 2 |
> | 10002 | Mouse House | 0 |
> | 10003 | Wascals | 1 |
> | 10004 | Yosemite Place | 1 |
> | 10005 | E Fudd | 1 |
> +---------+----------------+---------+
>
> -- 列出所有产品以及订购数量量,包括没有⼈人订购的产品;
> select products.prod_id,products.prod_name,count(orderitems.order_num) AS num_ord
> from products left join orderitems
> on products.prod_id = orderitems.prod_id
> group by products.prod_id;
> ```
> **表联结注意事项**
>
> * 保证使⽤用正确的联结条件,否则将返回不不正确的数据。
> * 应该总是提供联结条件,否则会得出笛卡⼉儿积。
> * 在一个联结中可以包含多个表,甚至对于每个联结可以采⽤用不同的联结类型。虽然这样做是合法的,一般也很有用,但应该在一起测试它们前,分别测试每个联结。这将使故障排除更为简单
### 组合查询
MySQL也允许执行多个查询多条SELECT语句句并将结果作为单个查询结果集返回。这些组合查询通常称为并union或复合查询compound query
**UNION规则**
* UNION必须由两条或两条以上的SELECT语句组成语句之间用关键字UNION分隔因此如果组合4条SELECT语句句将要使用3个UNION关键字
* UNION中的每个查询必须包含相同的列、表达式或聚集函数不过各个列不需要以相同的次序列出
* 列数据类型必须兼容类型不必完全相同但必须是DBMS可以隐含地转换的类型例如不同的数值类型或不同的日期类型
> 举例假如需要价格小于等于5的所有物品的一个列表而且还想包括供应商1001和1002生产的所有物品。
>
> ```mysql
> SELECT vend_id,prod_id,prod_price FROM products WHERE prod_price <= 5
> UNION
> SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id in(1001,1002);
>
> -- 查询结果
> +---------+---------+------------+
> | vend_id | prod_id | prod_price |
> +---------+---------+------------+
> | 1003 | FC | 2.50 |
> | 1002 | FU1 | 3.42 |
> | 1003 | SLING | 4.49 |
> | 1003 | TNT1 | 2.50 |
> | 1001 | ANV01 | 5.99 |
> | 1001 | ANV02 | 9.99 |
> | 1001 | ANV03 | 14.99 |
> | 1002 | OL1 | 8.99 |
> +---------+---------+------------+
>
> -- UNION会从查询结果集中自动去除了重复的行 这是UNION的默认行为但是如果需要可以改变它。
> -- 如果想返回所有匹配的行可使用UNION ALL
> SELECT vend_id,prod_id,prod_price FROM products WHERE prod_price <= 5
> UNION ALL
> SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id in(1001,1002);
>
> -- 结果
> +---------+---------+------------+
> | vend_id | prod_id | prod_price |
> +---------+---------+------------+
> | 1003 | FC | 2.50 |
> | 1002 | FU1 | 3.42 | -- 重复数据
> | 1003 | SLING | 4.49 |
> | 1003 | TNT1 | 2.50 |
> | 1001 | ANV01 | 5.99 |
> | 1001 | ANV02 | 9.99 |
> | 1001 | ANV03 | 14.99 |
> | 1002 | FU1 | 3.42 | -- 重复数据
> | 1002 | OL1 | 8.99 |
> +---------+---------+------------+
> ```
>
> **对组合查询结果排序**
>
> SELECT语句的输出用ORDER BY子句排序。在⽤UNION组合查询时只能使⽤一条ORDER BY子句它必须出现在最后一条SELECT语句之后。**ORDER BY子句是对整个结果集排序**
>
> ```mysql
> SELECT vend_id,prod_id,prod_price FROM products WHERE prod_price <= 5
> UNION
> SELECT vend_id,prod_id,prod_price FROM products WHERE vend_id in(1001,1002)
> ORDER BY prod_price;
>
> -- 查询结果
> +---------+---------+------------+
> | vend_id | prod_id | prod_price |
> +---------+---------+------------+
> | 1003 | FC | 2.50 |
> | 1003 | TNT1 | 2.50 |
> | 1002 | FU1 | 3.42 |
> | 1003 | SLING | 4.49 |
> | 1001 | ANV01 | 5.99 |
> | 1002 | OL1 | 8.99 |
> | 1001 | ANV02 | 9.99 |
> | 1001 | ANV03 | 14.99 |
> +---------+---------+------------+
> ```
## MySQL事务
事务Transaction是由⼀系列对系统中数据进行访问与更新的操作所组成的一个程序执行逻辑单元。
![](https://i.loli.net/2020/11/13/mEoWeQDFin72Rhd.png)
事务的基本语法:
```mysql
start transaction;或者 begin;
-- 事务操作的语句
commit; -- 使得当前的修改确认
rollback; -- 使得当前的修改被放弃
```
### 事务的ACID特性
1. **原子性Atomicity**
事务的原子性是指事务必须是一个原子的操作序列单元。事务中包含的各项操作在一次执行过程中,要么全部执行成功,要么全部执行失败。
事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,
会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体。
2. **一致性Consistency**
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,不能时数据发生错乱
3. **隔离性Isolation**
事务的隔离性是指在**并发环境**中,**并发的事务**是互相隔离的,各有各自的数据空间。
4. **持久性Duration**
事务的持久性是指事务一旦提交后,数据库中的数据必须被永久的保存下来。即使服务器系统崩溃或服务器宕机,只要数据库重新启动,那么一定能够将其恢复到事务成功结束后的状态。
### 事务并发常见问题
* 脏读Dirty Read读取到了没有提交的数据。
例如事务A读取了事务B更新的数据然后B回滚操作那么A读取到的数据就是脏数据。
* 不可重复读Unrepeatale Read同⼀条命令返回不同的结果集
例如:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中对数据作了更新并提交导致事务A多次读取同一数据时结果不一致。
* 幻读Phantom Read重复查询的过程中数据就发生了量的变化。
### 事务的隔离级别
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
| -------------------------- | ---- | ---------- | ------ |
| 读未提交(READ_UNCOMMITTED) | 允许 | 允许 | 允许 |
| 读已提交(READ_COMMITTED) | 禁止 | 允许 | 允许 |
| 可重复读(REPEATABLE_READ) | 禁止 | 禁止 | 可能会 |
| 顺序读(SERIALIZABLE) | 禁止 | 禁止 | 禁止 |
> 4种事务隔离级别从上往下级别越高并发性越差安全性就越高。 一般数据默认级别是读已提交或可重复读。
> **查看和设置事务隔离级别的语句**
>
> ```mysql
> -- 查看当前会话中事务的隔离级别
> select @@tx_isolation;
> -- 设置当前会话中的事务隔离级别
> set session transaction isolation level read uncommitted | read committed | repeatable read | SERIALIZABLE
> ```
1. **读未提交(READ_UNCOMMITTED)**
该隔离级别允许脏读取,其隔离级别是最低的。一个事务正在处理某⼀数据,并对其进行了更新,但同时尚未完成事务,因此还没有提交事务,而与此同时,允许另一个事务也能够访问该数据。
2. **读已提交(READ_COMMITTED)**
不同的事务执行的时候只能获取到已经提交的数据。 这样就不会出现上面的脏读的情况了。但是在同一个事务中执行同一个读取,结果不一致,即不可重复读问题
3. **可重复读(REPEATABLE_READ)**
保证在事务处理过程中,多次读取同一个数据时,该数据的值和事务开始时刻是一致的。因此该事务级别限制了不可重复读和脏读,但是有可能出现幻读的数据。
4. **顺序读(SERIALIZABLE)**
最严格的事务隔离级别,不允许事务并发,必须依次排序执行。
**不同的隔离级别的锁的情况**
1. 读未提交RU: 有行级的锁没有间隙锁。它与RC的区别是能够查询到未提交的数据。
2. 读已提交RC有行级的锁没有间隙锁读不到没有提交的数据。
3. 可重复读RR有行级的锁也有间隙锁每次读取的数据都是一样的并且没有幻读的情况。
4. 序列列化S有行级锁也有间隙锁读表的时候就已经上锁了。
## MySQL存储过程
存储过程简单来说就是为以后的使用而保存的一条或多条MySQL语句的集合。
存储过程就像脚本语⾔言中函数定义⼀样是一组为了完成特定功能的SQL语句集经过编译之后存储在数据库中在需要时直接调用。
**创建存储过程** `create procedure 存储过程名()`
> `\d //`修改MySQL默认的语句结尾符`;`改为`//` 。
>
> `create procedure 存储过程名()` 创建语句
>
> `BEGIN`和`END`语句用来限定存储过程体
```mysql
-- 定义存储过程 向users表中循环插入80条数据
\d //
create procedure p1()
begin
set @i=10;
while @i<90 do
insert into users values(null,concat('user:',@i),@i,0); --
set @i=@i+1;
end while;
end;
//
```
**调用存储过程** `call 存储过程名()`
**查看存储过程**`show create procedure 存储过程名\G`
**删除存储过程**`drop procedure 存储过程名`
## MySQL触发器
触发器是指MySQL**响应**写操作(增、删、改)而**自动执行**的一条或一组定义在BEGIN和END之间的MySQL语句。
或可理理解为:提前定义好一个或一组操作,在指定的SQL操作前或后来触发指定的SQL自动执行触发器就像是JavaScript中的事件一样。
**触发器语法**
```mysql
-- 创建触发器
\d //
CREATE TRIGGER trigger_name trigger_time trigger_event
ON tbl_name FOR EACH ROW
BEGIN
trigger_stmt;
END;
//
\d ; -- 结束之后要把语句结束符改回来
-- 说明:
# trigger_name触发器名称
# trigger_time:触发时间可取值BEFORE或AFTER
# trigger_event触发事件可取值INSERT、UPDATE或DELETE。
# tb1_name指定在哪个表上
# trigger_stmt触发理SQL语句。
-- 查看所有的 触发器器
show triggers\G;
-- 删除触发器
drop trigger trigger_name;
```
> 在使用触发器时,可以建立虚拟表来方便某些操作
>
> * 在INSERT触发器代码内可引用⼀个名为NEW的虚拟表访问被 插入的行;
> * 在DELETE触发器代码内可引用一个名为OLD的虚拟表访问被删除的行;
> * OLD中的值全都是只读的不能更新。
> * 在AFTER DELETE的触发器中无法获取OLD虚拟表
> * 在UPDATE触发器代码中
> * 可以引用一个名为OLD的虚拟表访问更新以前的值
> 可以引用一个名为NEW的虚拟表访问新更新的值;
## MySQL的视图
**视图的定义及特性**
视图是虚拟的表。与包含数据的表不一样,视图只包含使用时动态检索数据的查询语句。
视图本身不不包含数据,它们返回的数据是从其他表中检索出来的。
**视图的作用**
* 重用SQL语句简化复杂的SQL操作。在编写查询后可以方便地重用它而不必知道它的基本查询细节。
* 保护数据。可以给用户授予表的特定部分的访问权限而不是整个表的访问权限。
* 更改数据格式和表示。视图可返回与底层表的表示和格式不同的数据。
> **注意:视图不能索引,也不不能有关联的触发器或默认值**
**视图的语法和使用**
```mysql
-- 创建视图
create view 视图名 as 要封装的select语句;
-- 例如:
create view v_users as select id,name,age from users where age >= 25 and age<= 35;
-- 查看当前库中所有的视图
show tables; -- 可以查看到所有的表和视图
show table status where comment='view'\G; -- 只查看当前库中的所有视图
-- 删除视图v_t1:
drop view 视图名;
```
## MySQL索引与优化
### 索引概述
**定义**
MySQL官方对索引的定义为**索引(Index)是帮助MySQL高效获取数据的数据结构。**
索引类似图书的目录是一种有序结构可以提高数据检索的效率降低数据库的IO成本。
**分类**
| 索引类型 | 说明 |
| -------- | ------------------------------------------------------------ |
| 主键索引 | 根据主键建立的索引。**不允许重复,不允许空值**。<br>如果表中没有定义主键InnoDB 会选择一个唯⼀的非空索引代替如果没有这样的索引InnoDB 会隐式定义一个主键来作为聚簇索引。 |
| 唯一索引 | 用来建立索引的列的值必须是**唯一的,允许空值** |
| 普通索引 | 用表中普通列构建的索引,没有任何限制 |
| 全文索引 | 用大文本对象的列构建的索引5.6之前MyISAM支持InnoDB不支持8.0之前不支持中文。) |
| 组合索引 | 用多个列组合构建的索引,这多个列的值不允许空值,**需遵循“最左”原则** |
```mysql
-- 创建索引和删除索引
-- 1.主键索引
-- 1.创建表时,直接创建主键索引 PRIMARY KEY
CREATE TABLE users(
id int NOT NULL AUTO_INCREMENT PRIMARY KEY
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 2.修改时添加主键和自增
alter table users modify uid int primary key AUTO_INCREMENT;
-- 删除主键索引注意需要先取消自增,再删除主键
-- 先取消自增,修改字段
alter table users modify uid int;
-- 删除主键
alter table users drop primary key;
-- 2.唯一索引
-- 1.创建表时,直接创建唯一索引UNIQUE KEY
CREATE TABLE users(
name varchar(10) NOT NULL ,
UNIQUE KEY name(name), -- name为索引名
)ENGINE=InnoDB DEFAULT CHARSET-utf8mb4
-- 2.添加唯一索引UNIQUE当前列要求唯一但允许为空
alter table users add untque u_name(name); -- u_name为索引名
-- 删除唯一索引
alter table users drop index u_name;
-- 3.普通索引
-- 1.创建表时,直接创建普通索引 KEY
CREATE TABLE users(
email varchar ( 10 ) NOT NULL ,
KEY index_email(email) -- index_email为索引名
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
-- 2.添加索引
alter table users add index in_email(email);
-- 删除普通索引
drop index in_email on users;
-- 4.添加全文索引
ALERT TABLE 表名 ADD FULLTEXT INDEX 索引名(要建立索引的字段);
-- 5.组合索引
-- 添加索引
alter table users add index in_x(email,phone,uname)
-- 删除索引
alter table users drop index in_x;
```
### 索引原理-索引与B+Tree
> **哈希索引**
>
> 只有memory内存存储引擎支持哈希索引哈希索引用索引列的值计算该值的hashCode然后在hashCode相应的位置存执该值所在行数据的物理位置因为使用散列算法因此访问速度非常快但是一个值只能对应一个hashCode而且是散列的分布方式因此哈希索引不支持范围查找和排序的功能。
正常情况下如果不指定索引的类型那么一般是指B+Tree索引。
存储引擎以不同的方式使用B+Tree索引。性能也各有不同InnoDB时按照原数格式进行存储的。
首先要了解B+树之前我们先了解一下B树**B树是一种自平衡树状结构一般多用于存储系统上**,比如数据库或文件系统。
> 一个n阶的B树每个节点可以存储n-1个值
![](https://i.loli.net/2020/11/14/R9swUcgBDSIWZ5p.png)
可以看到B树每个叶子节点都带有数据在效率上还是存在一些弊端可以进行优化提高查询效率便演变出了B+树,如下图所示
![image-20201114211729600](https://i.loli.net/2020/11/14/FeBMcODgiwTVfqA.png)
使用B+树的优势
1. 磁盘读写代价更低
B树的数据和索引都在同一个节点上那么每个块中包含的索引是少量的如果想要取出比较深层的数据意味着要读取更多的块才能得到想要的索引和数据那么就增加了IO次数
而B+树中每个块能存储的索引是B树的很多倍那么获取比较深层的数据也只需要读取少量的块
就可以那么就减少了磁盘的IO次数
2. 随机IO的次数更少
随机I/O是指读写操作时间连续但访问地址不连续时长约为10ms。
顺序I/O是指读取和写入操作基于逻辑块逐个连续访问来自相邻地址的数据时长约为0.1ms
在相同情况下B树要进行更多的随机IO而B+树需要更多的顺序IO因此B+树,效率也更快
3. 查询速度更稳定
由于B+Tree非叶子节点不存储数据data),因此所有的数据都要查询至叶子节点,而叶子节点的
高度都是相同的,因此所有数据的查询速度都是一样的。
### 聚簇索引和非聚簇索引
**聚簇索引:**索引即数据,找到索引便找到了数据
**非聚簇索引:**索引是一个文件数据在另一个文件根据索引文件找到数据的key值然后到数据文件中根据key值找到数据
![](https://i.loli.net/2020/11/14/g98ev1TwkP5cAUS.png)
> **MyISAM的索引方案**
>
> InnoDB中索引即数据也就是聚簇索引的那棵B+树的叶子节点中已经把所有完整的用户记录都包含了了而MyISAM的索引方案虽然也使用树形结构但是却将索引和数据分开存储也就是把索引信息单独存到一个文件中这个文件称为索引文件。
>
> MyISAM会单独为表的主键创建⼀个索引只不过在索引的叶子节点中存储的不是完整的数据记录而是主键值 + 行号的组合。也就是先通过索引找到对应的行号再通过行号去找对应的记录其它非主键索引也是一样的这种情况我们称为“回行”。所以在MyISAM中所有的索引都是非聚簇索引也叫二级索引。
>
> ![](https://i.loli.net/2020/11/14/PbsI1ugyhd9UZGz.png)
>
> **MyISAM和InnoDB的区别**
>
> * 数据存储方式:
> * InnoDB由两种文件组成表结构、数据和索引
> * MyISAM由三种文件组成表结构、数据、索引
>
> * 索引的方式:
> * 索引的底层都是基于B+Tree的数据结构建立
> * InnoDB中主键索引为聚簇索引辅助索引是非聚簇索引
> * MyISAM中数据和索引存在不同的文件中因此都是非聚簇索引
> * 事务的支持:
> * InnoDB支持事务
> * MyISAM不支持事务
### 慢查询与SQL优化
#### 慢查询与Explain执行计划
MySQL的慢查询全名是慢查询日志是MySQL提供的一种日志记录用来记录在MySQL中响应时间超过阀值的语句。
默认情况下MySQL数据库并不启动慢查询目思需要手动来设置这个参数。如果不是调优需要的话一般不建议启动该参数开启慢查询日志会或多或少带来一定的性能影响。
![](https://i.loli.net/2020/11/14/dlLvRoOMuDXxQY8.png)
**Explain执行计划**
一条查询语句在经过MySQL查询优化器的各种基于成本和规则的优化会后生成一个所谓的执行计划。这个执行计划展示了接下来具体执行查询的方式比如多表连接的顺序是什么对于每个表采用什么访问方法来具体执行查询等等。MySQL为我们提供了EXPLAIN语句来帮助我们查看某个语句的具体执行计划。
![](https://i.loli.net/2020/11/14/V5hRgPtf2BxEYM1.png)
| 参数 | 参数解释 |
| ------------- | -------------------------------------------------------- |
| id | 在一个大的查询语句中每个 SELECT关键字都对应一个唯一的 id |
| select_type | SELECT关键字对应的那个查询的类型 |
| table | 表名 |
| partitions | 匹配的分区信息 |
| type | 针对单表的访问方法 |
| possible_keys | 可能用到的索引 |
| key | 实际上使用的索引 |
| key_len | 实际使用到的索引长度 |
| ref | 当使用索引列等值查询时,与索引列进行等值匹配的对象信息 |
| rows | 预估的需要读取的记录条数 |
| filtered | 某个表经过搜索条件过滤后剩余记录条数的百分比 |
| Extra | 一些额外的信息 |
### SQL优化
**索引优化**
* 适当建立索引
* 创建并使用自增数字来建立主键索引
* 为经常作为where条件的字段建立索引
* 添加索引的字段尽可能的保持唯一性
* 可考虑使用组合索引并进行*索引覆盖*(多个字段组合成一个联合索引,在查询时,所要的字段和查询条件中的索引是一致的)
* 索引绝不是加的越多越好每建立一个索引都会建立一棵B+树,并且需要维护,很费性能和存储空间。
* 合理使用索引,查询时避免索引失效
* 不要在查询的索引列上使用函数
* 不要在查询的索引列上进行运算
* 避免查询条件左右类型不匹配发生隐式转换
* 使用like模糊查询时避免通配符%放在第一位
* 多个单列索引并不是最佳选择,可以使用组合索引
* 使用组合查询时谨记最左前缀原则(从最左字段开始使用索引:查询条件中使用了组合索引的第一个字段,索引才会被使用。因此,在组合索引中索引列的顺序至关重要。如果不是按照索引的最左列开始查找,则无法使用索引。)
**SQL语句的优化**
* 避免嵌套语句(子查询)
* 避免多表查询(复杂查询简单化)

View File

@ -0,0 +1,484 @@
---
title: XML和JSON的使用java
date: 2020-10-24 16:24:49
tags:
- Java
- XML
- JSON
categories:
- Java基础
---
## XML
### 概述
[XML](https://baike.baidu.com/item/%E5%8F%AF%E6%89%A9%E5%B1%95%E6%A0%87%E8%AE%B0%E8%AF%AD%E8%A8%80/2885849?fromtitle=xml&fromid=86251&fr=aladdin)全称可扩展标记语言eXtensible Markup Language。是一种用于标记电子文件使其具有结构性的标记语言。
<!-- more -->
> 在电子计算机中,标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种的信息比如文章等。它可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。 它非常适合万维网传输提供统一的方法来描述和交换独立于应用程序或供应商的结构化数据。是Internet环境中跨平台的、依赖于内容的技术也是当今处理分布式结构信息的有效工具。早在1998年W3C就发布了XML1.0规范使用它来简化Internet的文档信息传输。
**特性:**
1. xml具有平台无关性, 是一门独立的标记语言.
2. xml具有自我描述性
**用途**
1. 网络数据传输
2. 数据存储
3. 配置文件
> .XML文件是保存XML数据的一种方式XML数据也可以以其他的方式存在如在内存中构建XML数据。不要将XML语言狭隘的理解成XML文件。
###XML语法
#### 基本语法
在XML文档开头要先写XML文档声明格式如下
```xml
<?xml version="1.0" encoding="UTF-8"?>
```
XML文档正文都是由一个个的**标记**组成的,包含:
* 开始标记(开放标记): <标记名称>
* 结束标记(闭合标记): </标记名称>
* 标记内容: 开始标记与结束标记之间 ,是标记的内容。
> 标记名称: 自定义名称,必须遵循以下命名规则:
>
> 1. 名称可以含字母、数字以及其他的字符
> 2. 名称不能以数字或者标点符号开始
> 3. 名称不能以字符 “xml”或者 XML、Xml开始
> 4. 名称不能包含空格,不能包含冒号(:
> 5. 名称区分大小写
例如 ,我们通过标记, 描述一个名字:
```xml
<name>答案</name>
```
**注意:**
1. 一个XML文档中必须有且且仅允许有一个根标记。
2. 标记可以嵌套, 但是不允许交。
3. 标记名称 允许重复
4. 标记的层级称呼 (子标记,父标记 ,兄弟标记,后代标记 ,祖先标记),例如下面代码:
```xml
<persons>
<person>
<name>张三</name>
<length>180cm</length>
</person>
<person>
<name>李四</name>
<length>200cm</length>
</person>
</persons>
```
name是person的子标记是person的后代标记是persons的后代标记是length的兄弟标记。person是name的父标记。persons是name的祖先标记。
5. 标记除了开始和结束 , 还可以包含属性。标记中的属性,在标记开始时描述,由属性名和属性值组成。
在开始标记中, 描述属性可以包含0-n个属性每一个属性是一个键值对!
属性名不允许重复 ,键与值之间使用等号连接, 多个属性之间使用空格分割,属性值 必须被引号引住。例如:
```xml
<persons>
<person id="10001" groupid="1">
<name>李四</name>
<age>18</age>
</person>
</persons>
```
6. 可以在XML文档中写注释但是不能写在文档声明前不能嵌套注释。
格式如下:
```xml
<!-- 注释 -->
```
#### 语法进阶CDATA
CDATA 是不会被 XML 解析器解析的文本数据。像 "<" 和 "&" 字符在 XML 元素中都是非法的。
> "<" 会产生错误,因为解析器会把该字符解释为新元素的开始。
>
> "&" 会产生错误,因为解析器会把该字符解释为字符实体的开始。
某些文本,比如 JavaScript 代码,包含大量 "<" 或 "&" 字符。为了避免错误,可以将脚本代码定义为 CDATA。CDATA 部分中的所有内容都会被解析器忽略。定义格式如下:
```xml
<![CDATA[脚本代码]]>
```
### Java解析XML
在java中XML可以通过下面四种方式解析
1. SAX解析
2. DOM解析
3. JDOM解析
4. DOM4J解析
其实也可以说成SAX和DOM两种解析方式因为后面两种也属于DOM解析是由DOM解析的基础上扩展来的只是用与Java。
#### SAX解析
解析方式是事件驱动机制 !
SAX解析器**逐行读取**XML文件进行解析 ,每当解析到一个标签的**开始/结束/内容/属性**时,触发事件。我们可以编写程序在这些事件发生时,进行相应的处理。
> **优点:**
>
> 1. 分析能够立即开始,而不是等待所有的数据被处理
> 2. 逐行加载,节省内存。有助于解析大于系统内存的文档
> 3. 有时不必解析整个文档,它可以在某个条件得到满足时停止解析。
>
> **缺点:**
>
> 1. 单向解析,无法定位文档层次,无法同时访问同一文档的不同部分数据(因为逐行解析当解析第n行时第n-1行已经被释放了无法再进行操作了)。
> 2. 无法得知事件发生时元素的层次,只能自己维护节点的父/子关系.
> 3. 只读解析方式无法修改XML文档的内容。
#### DOM解析
是用与平台和语言无关的方式表示XML文档的官方W3C标准分析该结构通常需要**加载整个文档**和内存中建立文档树模型。程序员可以通过操作文档树,来完成数据的获取、修改、删除等.
> **优点:**
>
> 1. 文档在内存中加载,允许对数据和结构做出更改.
> 2. 访问是双向的,可以在任何时候在树中双向解析数据。
>
> **缺点:**
>
> 1. 文档全部加载在内存中,消耗资源大.
#### JDOM解析
目的是解析为Java特定文档模型它简化与XML的交互并且比使用DOM实现更快。由于是第一个Java特定模型JDOM一直得到大力推广和促进。
> 优点:
>
> 1. 使用具体类而不使用接口简化了DOM的API。
> 2. 大量使用了Java集合类方便了Java开发人员。
>
> 缺点:
>
> 1. 没有较好的灵活性。
> 2. 性能不是那么优异。
#### DOM4J解析
它是JDOM的一种智能分支。它合并了许多超出基本XML文档表示的功能包括集成的XPath支持、XML Schema支持以及用于大文档或流化文档的基于事件的处理。它还提供了构建文档表示的选项。
DOM4J是一个非常优秀的Java XML API具有性能优异、灵活性好、功能强大和极端易用使用的特点同时它也是一个开放源代码的软件。如今你可以看到越来越多的Java软件都在使用DOM4J来读写XML。
##### DOM4J解析XML
**步骤:**
1. 引入DOM4j的jar包 dom4j.jar
2. 创建一个指向XML文件的输入流
```java
FileInputStream fis = new FileInputStream("xml文件的地址");
```
3. 创建一个XML读取工具对象`SAXReader`
```java
SAXReader sr = new SAXReader();
```
4. 使用读取工具对象读取XML文档的输入流 并得到文档对象`Document`
```java
Document doc = sr.read(fis);
```
5. 通过文档对象, 获取XML文档中的根元素对象 `Element root`
```java
Element root = doc.getRootElement();
```
**文档对象 `Document`**
指的是加载到内存的 整个XML文档。常用方法:
1. 通过文档对象, 获取XML文档中的根元素对象
```java
Element root = doc.getRootElement();
```
2. 添加根节点
```java
Element root = doc.addElement("根节点名称");
```
**元素对象 `Element`**
指的是XML文档中的单个节点。常用方法
| 方法 | 描述 |
| -------------------------------------------- | -------------------------------------------- |
| `String getName()` | 获取当前节点的标记名称 |
| `String getText()` | 获取节点内容 |
| `void setText(String s)` | 设置节点内容 |
| `String attributeValue(String s)` | 获取节点的属性值s表示属性名称 |
| `void addAttribute(String key,String value)` | 添加属性 key属性名value属性值 |
| `Element element(String name)` | 根据子节点名称获取匹配名称的第一个子节点对象 |
| `List<Element> elements()` | 获取所有的子节点对象 |
| `String elementText(String s)` | 返回子节点内容s表示子标签名称 |
| `Element addElement(String name)` | 添加子节点 name子节点名称 |
**解析本地文件案例**
![](https://i.loli.net/2020/10/24/DWNRyanEpfSKIt9.png)
**解析网络文件案例**
![](https://i.loli.net/2020/10/24/yR6wnKSqAjibEgI.png)
##### DOM4J - XPATH解析XML
XPATH就是通过路径快速的查找一个或一组元素
| 标记 | 解释 |
| ---- | ------------------------------------------------------------ |
| / | 从根节点开找 |
| // | 查找后代节点 |
| . | 查找当前节点 |
| … | 查找父节点 |
| @ | 选择属性,属性使用方式:<br>[@属性名=‘值’] <br>[@属性名>‘值’]<br>[@属性名<‘值’] <br>[@属性名!=‘值’] |
例如在我们解析本地文件案例中有一个books.xml文件如果我们想找到 “三国演义”这个元素XPATH 路径k可以这样写
```xml
//book[@id='1001']//name
```
通过Node类的两个方法, 来完成查找(Node是 Document 与 Element 的父接口)
方法1根据路径表达式 查找匹配的单个节点,如果结果有多个,只取第一个
```java
Node e = selectSingleNode("路径表达式");
```
方法2根据路径表达式 查找匹配的所有节点
```java
List<Node> es = selectNodes("路径表达式");
```
例子:
![](https://i.loli.net/2020/10/24/dptXgi5PVfseMKL.png)
![image-20201024011319670](https://i.loli.net/2020/10/24/IXvg15HAyc8KQ4J.png)
### Java生成XML
**步骤:**
1. 通过文档帮助器 (`DocumentHelper`) ,创建空的文档对象
```java
Document doc = DocumentHelper.createDocument();
```
2. 通过文档对象,向其中添加根节点
```java
Element root = doc.addElement("根节点名称");
```
3. 通过根节点对象root , 丰富我们的子节点
```java
Element e = root.addElement("元素名称");
```
4. 创建一个文件输出流 ,用于存储XML文件
```java
FileOutputStream fos = new FileOutputStream("要存储的位置");
```
5. 将文件输出流, 转换为XML文档输出流
```java
XMLWriter xw = new XMLWriter(fos);
```
6. 写出文档
```java
xw.write(doc);
```
7. 释放资源
```java
xw.close();
```
**例子**
![image-20201024014247166](https://i.loli.net/2020/10/24/wJnlYCycOIZ2jVk.png)
####XStream的使用
快速的将Java中的对象, 转换为 XML字符串.
使用步骤:
1. 创建XStream 对象
```
XStream x = new XStream();
```
2. 修改类生成的节点名称 (默认节点名称为 包名.类名)
```
x.alias("节点名称",类名.class);
```
3. 传入对象 , 生成XML字符串
```
String xml字符串 = x.toXML(对象);
```
例子:
![image-20201024013927345](https://i.loli.net/2020/10/24/BMce4ZkQX85qbNi.png)
## JSON
### 概述
[JSON](https://baike.baidu.com/item/JSON/2462549?fr=aladdin)全称JavaScript Object Notation JS对象简谱 ,是一种轻量级的数据交换格式。
> 它基于 [ECMAScript](https://baike.baidu.com/item/ECMAScript) (欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
>
> JSON是[Douglas Crockford](https://baike.baidu.com/item/Douglas Crockford/5960317)在2001年开始推广使用的数据格式在2005年-2006年正式成为主流的数据格式雅虎和谷歌就在那时候开始广泛地使用JSON格式。
### json语法
> 该部分内容参考自https://www.sojson.com/json/json_syntax.html
>
> 版权所属SOJSON原创文章
>
> 原文地址https://www.sojson.com/json/json_syntax.html
**json 语法规则**
- **数据在名称/值对中**,也就是我们常说的键值对,用逗号分隔
- **花括号{}保存对象**
- **方括号[]保存数组**
**JSON 数据**的书写格式是:`{Key:Value}`、`{Key:Array}`。前面是键,中间是英文的“:”(冒号),然后是值。但是注意的是如果是字符串,严格来说都是要用英文双引号引起来的。例如:
```json
{"name":"answer"}
```
JSON数据的值可以是 **数字(整数或浮点数)、字符串(在双引号中)、逻辑值(`true` 或 `false`)、数组(在方括号中)、对象(在花括号中)、`null`**
**JSON对象**在花括号中,对象可以包含多个名称/值对,如下代码所示:
```json
{
"name": "answer",
"age": 21,
}
```
**JSON数组**在方括号("[]"中书写数组可包含多个对象如下“student”描述
```json
{
"student": [
{
"name": "answer",
"age": "21"
},
{
"name": "brian",
"age": "20"
},
{
"name": "joe",
"age": "25"
}
]
}
```
在上面的例子中,对象 "student" 是包含三个对象的数组。每个对象代表一条关于一个学生(姓名和年龄)的记录。
### Java解析转换JSON
> 将Java中的对象快速的转换为JSON格式的字符串。
>
> 将JSON格式的字符串, 转换为Java的对象。
Java官方未提供官方的json解析工具json的解析借助第三方工具完成。常见的第三方工具有谷歌的**Gson**和阿里巴巴的**fastjson**。在使用前都要先导入jar包可以从某hub上下载。
![](https://i.loli.net/2020/10/24/OxXGZVTL7avnmEk.png)
#### Gson
**将对象转换为JSON字符串**在需要转换JSON字符串的位置编写如下代码即可
```java
String json = new Gson().toJSON(要转换的对象);
```
![](https://i.loli.net/2020/10/24/axH4XYOTv9MK8Nq.png)
**将JSON字符串转换为对象**在需要转换Java对象的位置编写如下代码:
```java
对象 = new Gson().fromJson(JSON字符串,对象类型.class);
```
![](https://i.loli.net/2020/10/24/CXxaiUnwAqPYEOD.png)
#### FastJson
**将对象转换为JSON字符串**在需要转换JSON字符串的位置编写如下代码即可:
```java
String json=JSON.toJSONString(要转换的对象);
```
![](https://i.loli.net/2020/10/24/lRdcx8KVgMz69yp.png)
**将JSON字符串转换为对象**在需要转换Java对象的位置, 编写如下代码:
```java
类型 对象名=JSON.parseObject(JSON字符串, 类型.class);
//或者
List<类型> list=JSON.parseArray(JSON字符串,类型.class);
```
![](https://i.loli.net/2020/10/24/VE1laqAPfMgYvcG.png)
![](https://i.loli.net/2020/10/24/eDRPWEik5fpCO2s.png)

View File

@ -0,0 +1,89 @@
---
title: smartupload简单实现文件上传
date: 2020-12-12 14:01:24
tags:
- JavaWeb
- 文件上传
- smartupload
categories:
- JavaWeb
---
文件上传实质上就是客户端发起请求将一个大数据IO流上传到服务器
<!--more-->
**步骤:**
**1.将jar包添加到项目中smartupload.jar**
**2.创建smartupload对象并初始化**
```java
//创建对象
SmartUpload smartUpload = new SmartUpload();
//获得jsp的pageContent对象并初始化
PageContext pageContext = JspFactory.getDefaultFactory().getPageContext(this, req, resp, null, false, 1024, true);
smartUpload.initialize(pageContext);
//编码
smartUpload.setCharset("utf-8");
```
> **getPageContext()方法**
>
> ![](https://i.loli.net/2020/11/26/bJ7gEMCIVv83SDa.png)
>
> 参数的含义
>
> ![](https://i.loli.net/2020/11/26/hJzWE5XqgsLcpG3.png)
**3.调用SmartUpload对象的upload()方法上传文件**
```java
//文件上传
try {
smartUpload.upload();
} catch (SmartUploadException e) {
e.printStackTrace();
}
```
截止目前,文件就被上传到了服务器,但服务器并没有保存
**4. 保存文件到指定位置**
```java
/*保存文件*/
//得到smartUpload对象中文件数组的第1个文件
File file = smartUpload.getFiles().getFile(0);
//得到该文件的信息
String fileName = file.getFileName();
//指定存储路径
String path = "uploadfile/"+fileName;
//存储
try {
file.saveAs(path,SmartUpload.SAVE_VIRTUAL);
} catch (SmartUploadException e) {
e.printStackTrace();
}
```
至此,数据文件已经被存放到了某个指定路径下。接下来就可以自己决定如何在前端显示。
> `public void saveAs(String path, int optionSaveAs)`
>
> 其中path是另存的文件路径optionSaveAs是另存的选项该选项有三值
>
> * SAVEAS_PHYSICAL表明以操作系统的根目录为文件根目录另存文件
> * SAVEAS_VIRTUAL表明以Web应用程序的根目录为文件根目录另存文件
> * SAVEAS_AUTO则表示让组件决定
>
> 当Web应用程序的根目录存在另存文件的目录时它默认会选择SAVEAS_VIRTUAL否则会选择SAVEAS_PHYSICAL。
> smartupload常用方法
>
> ![image-20201126225644272](https://i.loli.net/2020/11/26/3AyUuBT54MoI1sP.png)
> smaryupload中文文档
>
> [https://www.cnblogs.com/mycodelife/archive/2009/04/26/1444132.html](https://www.cnblogs.com/mycodelife/archive/2009/04/26/1444132.html)

View File

@ -0,0 +1,233 @@
---
title: 一文搞懂AJAX技术
date: 2020-12-12 13:58:17
tags:
- JavaWeb
- JQuery
- AJAX
categories:
- JavaWeb
---
## AJAX简介
AJAXAsynchronous JavaScript and XML即异步的 JavaScript 和 XML。AJAX 是与服务器交换数据,在不重新加载整个页面的情况下更新部分网页的技术。
<!--more-->
ajax并非一种新的技术而是几种原有技术的结合体。它由下列技术组合而成
> 1. 使用CSS和XHTML来表示。
>
> 2. 使用DOM模型来交互和动态显示。
> 3. 使用XMLHttpRequest来和服务器进行异步通信。
> 4. 使用javascript来绑定和调用。
**AJAX 的核心是 XMLHttpRequest 对象。**
> 不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。
>
> IE 浏览器使用 ActiveXObject而其他的浏览器使用名为 XMLHttpRequest 的 JavaScript 内建对象
**AJAX属于前端技术通过JS代码来编写。**
## AJAX工作原理
Ajax的工作原理相当于在用户和服务器之间加了一个中间层(AJAX引擎)使用户操作与服务器响应异步化。并不是所有的用户请求都提交给服务器。像一些数据验证和数据处理等都交给Ajax引擎自己来做只有确定需要从服务器读取新数据时再由Ajax引擎代为向服务器提交请求。
![](https://i.loli.net/2020/11/26/SCFUDwdnKA8Mq1b.png)
浏览器的普通交互方式
![](https://i.loli.net/2020/11/26/vYZBjVX8T1kHieA.jpg)
浏览器的AJAX交互方式
![a3](https://i.loli.net/2020/11/26/sweN5ixgVCjq3KZ.jpg)
有了AJAX层用户页面可以不必等待服务器返回响应才可以进行下一个请求而是以异步的方式不同的AJAX请求互相不需要等待极大的提高了效率。
## XMLHttpRequest对象常用属性和方法
### 属性
**onreadystatechange 属性**
onreadystatechange 属性存有处理服务器响应的函数。 下面的代码定义一个空的函数,可同时对
onreadystatechange 属性进行设置:
```javascript
xmlHttp.onreadystatechange = function() {
//code
}
```
**readyState属性**
readyState 属性存有服务器响应的状态信息。每当 readyState 改变时onreadystatechange 函数就会被执行。
readyState 属性可能的值:
![image-20201126212659531](https://i.loli.net/2020/11/26/bQ8muwY2EXLc4PH.png)
向上面的 onreadystatechange 函数添加一条 If 语句,来测试我们的响应是否已完成(意味着可获得数据)
```javascript
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
//从服务器的response获得数据
}
}
```
**responseText 属性**
可以通过 responseText 属性来取回由服务器返回的数据。 在下面的代码中将时间文本框的值设置为等于responseText
```javascript
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
document.myForm.time.value = xmlHttp.responseText;
}
}
```
其它属性如下:
![](https://i.loli.net/2020/11/26/IYs3p7mf9ckCJXi.png)
### 方法
**open() 方法**
open() 有三个参数。第一个参数定义发送请求所使用的方法第二个参数规定服务器端脚本的URL第三个参数规定是否对请求进行异步地处理。
```javascript
xmlHttp.open("GET","test.jsp?key=xxx&key=xxx",true);
```
**send() 方法**
send() 方法将请求送往服务器。
```javascript
xmlHttp.send(null);
```
> open和send方法中参数的使用
>
> [https://blog.csdn.net/weixin_40292626/article/details/78708160](https://blog.csdn.net/weixin_40292626/article/details/78708160)
其他方法如下:
![](https://i.loli.net/2020/11/26/HQK42zNWruhafdR.png)
## AJAX实现方法
### 原生JS方法
实现AJAX的步骤如下
1. 创建XMLHttpRequest对象。
2. 设置请求方式。
3. 调用回调函数。
4. 发送请求。
**1. 创建XMLHttpRequest对象**
一般我们手写AJAX的时候首先要判断该浏览器是否支持XMLHttpRequest对象如果支持则创建该对象如果不支持则创建ActiveX对象。JS代码如下
```javascript
//第一步创建XMLHttpRequest对象
var xmlHttp;
if (window.XMLHttpRequest) {
//非IE
xmlHttp = new XMLHttpRequest();
} else if (window.ActiveXObject) {
//IE
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP")
}
```
**2. 设置请求方式**
```javascript
//第二步设置和服务器端交互的相应参数向路径http://localhost:8080/JsLearning3/getAjax准备发送数据
var url = "http://localhost:8080/JsLearning3/getAjax";
xmlHttp.open("POST", url, true);
```
**3. 调用回调函数**
```javascript
//第三步:回调函数
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == 4) {
if (xmlHttp.status == 200) {
var obj = document.getElementById(id);
obj.innerHTML = xmlHttp.responseText;
} else {
alert("AJAX服务器返回错误");
}
}
}
```
> `xmlHttp.status == 200`200指服务器状态码代表正确。
>
> 更多状态码可以看我前面讲JSP的那篇文章
>
> [https://blog.csdn.net/qq_40932102/article/details/110235296](https://blog.csdn.net/qq_40932102/article/details/110235296)
**4. 发送请求**
```javascript
//第四步:设置发送请求的内容和发送报送。然后发送请求
var uname= document.getElementsByName("userName")[0].value;
var upass= document.getElementsByName("userPass")[0].value ;
// 增加time随机参数防止读取缓存
var params = "userName=" + uname+ "&userPass=" +upass+ "&time=" + Math.random();
// 向请求添加HTTP头POST如果有数据一定要加
xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded;charset=UTF-8");
xmlHttp.send(params);
```
如果需要像 HTML 表单那样 POST 数据,要使用 setRequestHeader() 来添加HTTP头避免乱码。然后在 send() 方法中传入希望发送的数据。
### JQuery实现Ajax
使用原生js的方式实现ajax步骤繁琐方法、属性、常用值较多不好记忆。
使用JQuery实现Ajax只需要调用JQuery封装好的ajax()方法即可,它可以通过发送 HTTP请求加载远程数据是 jQuery 最底层的 Ajax 实现,具有较高灵活性。语法如下:
```javascript
$.ajax({
url:请求地址
type:"get | post | put | delete " 默认是get,
data:请求参数 {"id":"123","pwd":"123456"},
dataType:请求数据类型"html | text | json | xml | script | jsonp ",
success:function(data,dataTextStatus,jqxhr){ },//请求成功时
error:function(jqxhr,textStatus,error)//请求失败时
})
```
JQuery中也有简单的get()和post()方法可以使用
```javascript
$.get(url,data,function(result) { //通过远程 HTTP GET 请求载入信息。
//将服务器返回的数据显示到页面的代码
});
$.post(url,data,function(result) { //通过远程 HTTP POST 请求载入信息。
//将服务器返回的数据显示到页面的代码
});
//url:请求的路径
//data:发送的数据
//result自动接收从servlet打印流打印的字符串默认是String不能接收JSON格式
```
**返回的数据都被封装到了result变量里get/post()中返回时text类型ajax()中可以指定返回的数据类型**
根据传回的数据格式选择不同的方法如果是简单的字符串建议使用get/post(),如果传回的是复杂数据,**以JSON格式传回只能使用ajax**

View File

@ -0,0 +1,355 @@
---
title: 一文搞懂jSP
date: 2020-12-12 13:51:56
tags:
- JavaWeb
- jsp
- EL表达式
- JSTL标签库
categories:
- JavaWeb
---
## JSP简介
JSP全称Java Server Pages是由 Sun Microsystems 公司倡导和许多公司参与共同创建的一种使软件开发者可以响应客户端请求,而动态生成 HTML、XML 或其他格式文档的Web网页的技术标准在传统的网页HTML文件中插入Java程序段(Scriptlet)和JSP标记(tag)从而形成JSP文件。
<!--more-->
JSP 技术是以 Java 语言作为脚本语言的JSP 网页为整个服务器端的 Java 库单元提供了一个接口来服务于HTTP的应用程序。
**语法**
```jsp
声明标签: <%!变量或者方法声明%>
表达式标签: <%= 表达式%> 在页面上显示的效果
程序代码标签: <%java代码%> 页面上动态展示内容
<!-- html注释内容,查看源码时能看到 -->
<%-- jsp注释,查看页面源码时看不到 --%>
```
**原理**
<font color=red>JSP本质上也是servlet</font>
将jsp文件翻译成java文件并编译成class文件其中包含的HTML代码以流的方式被响应回浏览器显示
> **JSP中出现的状态码服务器状态码**
>
> 状态码是指由服务器根据HTTP协议所提交的信息返回的HTTP头信息代码。
>
> | 状态码 | 消息 | 描述 |
> | ------ | -------------------------- | ------------------------------------------------------------ |
> | 100 | Continue | 只有一部分请求被服务器接收,但只要没被服务器拒绝,客户端就会延续这个请求 |
> | 101 | Switching Protocols | 服务器交换机协议 |
> | 200 | OK | 请求被确认 |
> | 201 | Created | 请求时完整的,新的资源被创建 |
> | 202 | Accepted | 请求被接受,但未处理完 |
> | 300 | Multiple Choices | 一个超链接表用户可以选择一个超链接并访问最大支持5个超链接 |
> | 301 | Moved Permanently | 被请求的页面已经移动到了新的URL下 |
> | 302 | Found | 被请求的页面暂时性地移动到了新的URL下 |
> | 303 | See Other | 被请求的页面可以在一个不同的URL下找到 |
> | 400 | Bad Request | 服务器无法识别请求 |
> | 403 | Forbidden | 禁止访问所请求的页面 |
> | 404 | Not Found | 服务器无法找到所请求的页面 |
> | 405 | Method Not Allowed | 请求中所指定的方法不被允许 |
> | 500 | Internal Server Error | 请求不完整,服务器遇见了出乎意料的状况 |
> | 501 | Not Implemented | 请求不完整,服务器不提供所需要的功能 |
> | 502 | Bad Gateway | 请求不完整,服务器从上游服务器接受了一个无效的响应 |
> | 503 | Service Unavailable | 请求不完整,服务器暂时重启或关闭 |
> | 504 | Gateway Timeout | 网关超时 |
> | 505 | HTTP Version Not Supported | 服务器不支持所指定的HTTP版本 |
## JSP的内置对象
JSP中一共预先定义了9个对象分别为request、response、session、application、out、
pagecontext、config、page、exception
1. **request对象**
该对象代表了客户端的请求信息主要用于接受通过HTTP协议传送到服务器的数据。包括头信息、系统信息、请求方式以及请求参数等**request对象的作用域为一次请求。**所属类型:HttpServletRequest。
2. **response对象**
response 代表的是对客户端的响应主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域**它只在JSP页面内有效**。所属类型:HttpServletResponse
3. **session对象**
session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象用于保存该用户的信息跟踪用户的操作状态。session对象内部使用Map类来保存数据因此保存数据的格式为`"Key/value"`。 所属类型:HttpSession
4. **application对象**
application 对象可将信息保存在服务器中直到服务器关闭application对象中保存的信息会在整个应用中都有效。与session对象相比application对象生命周期更长类似于系统的「全局变量」。所属类型:ServletContext
5. **out 对象**
out 对象用于在Web浏览器内输出信息并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。例如:
```jsp
out.print("<script type='text/javascript'>alert('用户名不存在');location.href='index.jsp'</script>");
```
6. **pageContext 对象**
pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的在JSP页面中可以直接使用pageContext对象。
7. **config 对象**
config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时容器把某些信息通过config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。
8. **page 对象**
page 对象代表JSP本身只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量类似于Java编程中的 this 指针。
9. **exception 对象**
exception 对象的作用是显示异常信息,只有在包含 isErrorPage="true" 的页面中才可以被使用在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中可以使用try/catch关键字来处理异常情况 如果在JSP页面中出现没有捕获到的异常就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中然后在错误页面中处理相应的 exception 对象。
```jsp
<%--先在可能发生错误的页面中添加errorPage属性:--%>
<%@ page pageEncoding="utf-8" errorPage="error.jsp" contentType="text/html;charset=UTF-8" language="java" %>
<%--在error.jsp页面中设置isErrorPage="true" 的属性--%>
<%@ page language="java" isErrorPage="true" import="java.util.*" pageEncoding="UTF-8"%>
```
> **jsp对象的作用域:**
>
> pageContext < request < session < application
>
> pageContext :当前页面
>
> request:单次请求
> session:浏览器访问期间(会话期间)
> application:服务器启动期间,所存的数据可以跨浏览器
## JSP的指令
JSP指令用来设置整个JSP页面相关的属性如网页的编码方式和脚本语言。
语法格式如下:
```jsp
<%@ directive attribute="value" %>
directive指令名称 attribute 属性名 value:属性值
```
| 指令名称 | 描述 |
| -------- | ------------------------------------------------------- |
| page | 定义网页依赖属性比如脚本语言、error页面、缓存需求等等 |
| include | 包含其他文件 |
| taglib | 引入标签库的定义 |
1. **page指令**
Page指令为容器提供当前页面的使用说明一个JSP页面可以包含多个page指令
```jsp
<%@ page attribute="value" %>
```
page指令的属性
| 常用属性 | 属性值 | 属性描述 |
| ------------ | ------------------------- | ------------------------------------------------------------ |
| language | java | 解释该JSP文件时采用的语言一般为java语言默认为java |
| extends | 任何类的全名 | 编译该JSP文件时继承哪个类JSP为Servlet因此当指明继承普通类时需要实现Servlet的init、destroy等方法 |
| import | 引入该JSP中用到的类、包等 | import是唯一可以声明多次的page指令属性中间用英文逗号隔开<%@page import=包名.类名,包名.类名%> |
| session | true/false | 该JSP内是否内置Session对象如果为true则内置Session对象可直接使用否则反之默认为true |
| autoFlush | true/false | 是否运行缓存如果为true则使用out.println()等方法输出的字符串并不是立刻到达客户端服务器的而是暂时存到缓存里缓存满了或者程序行完毕或者执行out.flush()操作时才到客户端默认为true。 |
| buffer | none或者数字KB | 指定缓存大小当autoFlush设为true时有效例如<%@ page buffer=10kb%> |
| isThreadSafe | true/false | 是否线程安全如果为true则运行多个线程同时运行该jsp程序否则只运行一个线程其余线程等待默认为false |
| isErrorPage | true/false | 指定该页面是否为错误显示页面如果为true则该JSP内置有一个Exception对象 exception可直接使用否则没有默认为false |
| errorPage | 某个JSP页面的相对路径 | 指明一个错误页面如果该JSP程序抛出一个未捕捉的异常则转到 errorPage指定的页面errorPage指定的页面通常isErrorPage属性为true且内置的exception对象为未捕捉的异常 |
| contentType | 有效的文档类型 | 客户端浏览器根据该属性判断文档类型,例如 HTML格式为text/html、纯文本格式为text/plain、JPG图像为image/jpeg、GIF图像为image/gif、WORD文档为application/msword该属性常跟着charset设置编码一起作用是通知服务器和浏览器都使用同一个码表 |
| pageEncoding | 字符集编码如UTF-8 | 设置页面字符集编码 |
2. **Include指令**
JSP可以通过include指令来包含其他文件。被包含的文件可以是JSP文件、HTML文件或文本文件。包含的文件就好像是该JSP文件的一部分会被同时编译执行。
```jsp
<%@ include file="文件相对 url 地址" %>
```
3. **Taglib指令**
JSP API允许用户自定义标签一个自定义标签库就是自定义标签的集合。
Taglib指令引入一个自定义标签集合的定义包括库路径、自定义标签。
```jsp
<%@ taglib uri="uri" prefix="" %>
```
uri属性确定标签库的位置prefix属性指定标签库的前缀(可自定义)。
## EL表达式
ELExpression Language简化对象和变量访问的一种语法
```jsp
语法格式:${需要取出数据的键值}
```
当表达式没有指定变量或者对象的范围时那么容器会依次从pageContext—>request—>session—>application中查找该变量或对象我们可以通过隐含对象获得指定作用域的值
```jsp
${pageScope.key} 用于获取当前页面的属性值
${requestScope.key} 用于获取请求范围的属性值
${sessionScope.key} 用于获取会话范围的属性值
${applicationScope.key} 用于获取程序范围的属性值
```
<font color = red>EL表达式不可以直接取出变量只能通过将变量放入作用域的方式</font>
**EL中基础操作符**
EL表达式支持大部分Java所提供的算术和逻辑操作符
| **操作符** | **描述** |
| :--------- | :------------------------------- |
| . | 访问一个Bean属性或者一个映射条目 |
| [] | 访问一个数组或者链表的元素 |
| ( ) | 组织一个子表达式以改变优先级 |
| + | 加 |
| - | 减或负 |
| * | 乘 |
| / or div | 除 |
| % or mod | 取模 |
| == or eq | 测试是否相等 |
| != or ne | 测试是否不等 |
| < or lt | 测试是否小于 |
| > or gt | 测试是否大于 |
| <= or le | 测试是否小于等于 |
| >= or ge | 测试是否大于等于 |
| && or and | 测试逻辑与 |
| \|\| or or | 测试逻辑或 |
| ! or not | 测试取反 |
| empty | 测试是否空值 |
> **关于EL表达式更多内容可以参考[https://www.runoob.com/jsp/jsp-expression-language.html](https://www.runoob.com/jsp/jsp-expression-language.html)**
## JSTL
JSTL(JSP标准标签库)是一个JSP标签集合它封装了JSP应用的通用核心功能。
JSTL支持通用的、结构化的任务比如迭代条件判断XML文档操作国际化标签SQL标签。 除了这些它还提供了一个框架来使用集成JSTL的自定义标签。
根据JSTL标签所提供的功能可以将其分为5个类别。核心标签、格式化标签、sql标签、xml标签、jstl函数
> 要使用JSTL首先需要导入jar包
>
> 下载 jakarta-taglibs-standard-1.1.2.zip 包并解压,将 jakarta-taglibs-standard-1.1.2/lib/ 下的两个 jar 文
> 件standard.jar 和 jstl.jar 文件拷贝到 /WEB-INF/lib/ 下,并配置。
**语法:**
1. 在JSP页面中引入`<%@ taglib prefix=”页面使用的名称” uri=”功能范围的路径”%>`
| 功能范围 | 说明 | Uri | 前缀prefix |
| --------- | ---------- | ------------------------------------- | ---------- |
| core | 核心标签 | http://java.sun.com/jsp/jstl/core | c |
| i18n | 格式化标签 | http://java.sun.com/jsp/jstl/fmt | fmt |
| sql | sql标签 | http://java.sun.com/jsp/jstl/sql | sql |
| xml | xml标签 | http://java.sun.com/jsp/jstl/xml | x |
| functions | jstl函数 | http://java.sun.com/jsp/jstl/function | fn |
2. 通过标签库前缀和标记及属性进行操作`<前缀:标记 属性="值",属性="值">`
**核心标签**
核心标签有以下几种标记
* 表达式操作 out、set、remove、catch
* 流程控制 if、choose、when、otherwise
* 迭代操作 forEach、forTokens
* URL操作 import、param、url、redirect
常用的标记及其属性:
- c:set> 主要用来将变量存储至JSP范围中 或是JavaBean的属性或Map对象中
| 名称 | 说明 | 是否必须写 | 默认值 |
| -------- | -------------------- | ---------- | ------ |
| value | 要被存储的值 | 否 | 无 |
| var | 存入的变量名称 | 否 | 无 |
| scope | var变量的JSP范围 | 否 | Page |
| target | JavaBean或Map对象 | 否 | 无 |
| property | 指定target对象的属性 | 否 | 无 |
- c:out>主要用来显示数据的内容
| 名称 | 说明 | 是否必须写 | 默认值 |
| --------- | -------------------------------------- | ---------- | ------ |
| value | 需要显示出来的值 | 是 | 无 |
| default | 如果value的值为null则显示default的值 | 否 | 无 |
| escapeXml | 是否转换特殊字符,如:<转换成 & lt; | 否 | True |
- c:remove> 主要负责移除变量
| 名称 | 说明 | 是否必须写 | 默认值 |
| ----- | ---------------- | ---------- | ------ |
| var | 欲移除的变量名称 | 是 | 无 |
| Scope | var变量的jsp范围 | 否 | Page |
- c:if> 主要用于进行if判断,如果为true,则输出标签体中的内容
| 名称 | 说明 | 是否必须写 | 默认值 |
| ----- | --------------------------------------------- | ---------- | ------ |
| test | 表达式的结果为true则执行体内容false则相反 | 是 | 无 |
| var | 如果 用来存储test运算的结果(true或false) | 否 | 无 |
| scope | Var变量的JSP范围 | 否 | page |
- c:choose >,c:when >,c:otherwise > 作用相当于if-else
| 名称 | 说明 | 是否必须写 | 默认值 |
| ---- | --------------------------------------------- | ---------- | ------ |
| test | 表达式的结果为true则执行体内容false则相反 | 是 | 无 |
- c:forEach> 循环控制,它可以将数组,集合(Collection)中的成员循序浏览一遍。
| 名称 | 说明 | 必须 | 默认值 |
| --------- | ------------------------------------ | ---- | ------------ |
| var | 用来存放现在指定的成员 | 是 | 无 |
| items | 被迭代的集合对象需要使用EL表达式 | 否 | 无 |
| varStatus | 用来代指被迭代的集合对象 | 否 | 无 |
| begin | 开始的位置 | 否 | 0 |
| end | 结束的位置 | 否 | 最后一个成员 |
| step | 每次迭代的间隔数 | 否 | 1 |
**格式化标签**
常用的标记及其属性:
* < fmt:formatDate > 将日期类型格式化为指定模式的字符串
| 名称 | 说明 | 默认值 |
| ------- | ------------------------------------------------------------ | ------ |
| value | 将要被格式化的数据 | |
| pattern | 格式化的模式与SimpleDateFormat的参数设置一样,如yyyy-MM-dd | |
| var | 格式化后的字符串所要存放的变量若不指定var则会将格式化的结果直接显示在页面 | |
| scope | 变量存放的域属性空间 | page |
| type | 其取值为date、time、both表示给出的value是日期、时间、还是两者都包含 | date |
* < fmt:parseDate > 用于将指定字符串转化为日期类型
| 名称 | 说明 |
| ------- | ---------------- |
| value | 服务器获取的时间 |
| pattern | 转换的格式 |
| var | 页面显示的变量 |
* < fmt:formatNumber > 按照指定格式对数字进行格式化
| 名称 | 说明 |
| ---------------- | ----------------------------------- |
| maxIntegerDigits | 整数部分最多的位数 |
| minIntegerDigits | 整数部分最少的位数 |
| maxFrctionDigits | 小数部分最多的位数 |
| minFrctionDigits | 小数部分最少的位数 |
| var | 存储格式化结果的变量 |
| scope | var属性的作用域 |
| integerOnly | 是否只解析整型数true或者浮点数false |
> **关于JSTL更多内容可以参考[https://www.runoob.com/jsp/jsp-jstl.html](https://www.runoob.com/jsp/jsp-jstl.html)**

View File

@ -0,0 +1,329 @@
---
title: 一文搞懂java Servlet
date: 2020-12-12 13:49:39
tags:
- JavaWeb
- servlet
- session
- cookie
categories:
- JavaWeb
---
## servlet简介
ServletServer Applet全称Java Servlet是用Java编写的<font color=red>运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。</font>其主要功能在于交互式地浏览和修改数据生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口广义Servlet是指任何实现了这个Servlet接口的类一般情况下人们将Servlet理解为后者。
<!--more-->
下图显示了 Servlet 在 Web 应用程序中的位置。
![](https://i.loli.net/2020/11/26/sl8OL1tcj4WDmfN.png)
## Servlet工作模式
① 客户端发送请求至服务器
* 这些请求可以是显式的数据,包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单
* 也可以是隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
② 服务器启动并调用ServletServlet根据客户端请求生成响应内容并将其传给服务器
③ 服务器将响应返回客户端,同第①个,这些响应也可以是显式的数据或隐式的数据
## Servlet工作原理
(1)Servlet接口定义了Servlet与servlet容器之间的契约。这个契约是Servlet容器将Servlet类载入内存并产生Servlet实例和调用它具体的方法。<font color=red>在一个应用程序中每种Servlet类型只能有一个实例</font>
(2)用户请求使Servlet容器调用Servlet的Service()方法并传入一个ServletRequest对象和一个ServletResponse对象。这些对象都是由Servlet容器例如TomCat封装好的并不需要程序员去实现程序员可以直接使用。
* ServletRequest中封装了当前的Http请求ServletResponse表示当前用户的Http响应
(3)对于每一个应用程序Servlet容器还会创建一个ServletContext对象。这个对象中封装了上下文应用程序的环境详情。<font color=red>每个应用程序只有一个ServletContext</font>。每个Servlet容器也都有一个封装Servlet配置的ServletConfig对象。
## Servlet的使用
Java Servlet 是运行在带有支持 Java Servlet 规范的解释器的 web 服务器上的 Java 类。Servlet 可以使用 **javax.servlet****javax.servlet.http** 包创建,它是 Java 企业版的标准组成部分。它们之间的关系如下图所示:
![](https://i.loli.net/2020/11/26/1CgmXzM8NBK4vcx.png)
### 使用
创建一个类**实现Servlet接口**,重写其中的方法
```java
public class LoginServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//初始化方法
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest res, ServletResponse resp) throws ServletException, IOException {
//处理get/post请求的方法
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
//销毁的方法
}
}
```
**继承HttpServlet类常用**
```java
public class LoginServlet implements Servlet {
@Override
public void doGet(HttpServletRequest res, HttpServletResponse resp) throws ServletException, IOException {
//处理get请求的方法
}
@Override
public void doPost(HttpServletRequest res, HttpServletResponse resp) throws ServletException, IOException {
//处理get请求的方法
}
}
```
### 部署配置
容器Tomcat在得到客户端的请求后但不知道去交给哪一个servlet去处理所以需要进行部署有两种方式
**方式一web.xml文件部署Servlet的映射关系**
```xml
<servlet>
<servlet-name>自定义名称</servlet-name>
<servlet-class>处理请求的类的完整路径</servlet-class>
</servlet>
<servlet-mapping><!-- mapping 表示映射 -->
<servlet-name>自定义名称</servlet-name>
<url-pattern>请求名</url-pattern>
</servlet-mapping>
```
> 这个xml标签的执行顺序
>
> 请求过来以后->web.xml->servlet-mapping标签中的url-pattern标签中的内容和请求名进行匹配->匹配成功后找对应的servlet-mapping标签中的servlet-name->去servlet标签中找和上一个servlet-name相同的name值->去找servlet标签中的servlet-class中处理类的完整路径。
**方式二:@WebServlet注解**
**注解这个方式是Servlet3.0版本后才支持的**,它里面可以添加如下属性
| 属性名 | 类型 | 描述 |
| -------------------- | -------------- | ------------------------------------------------------------ |
| name | String | 指定Servlet 的 name 属性,默认为类的全限定名 |
| value或者urlPatterns | String | 指定Servlet处理的url。等价于web.xml中的`<url-pattern>`标签。 |
| asyncSupported | boolean | 指定Servlet是否支持异步操作模式 |
| displayName | String | 指定servlet的显示名 |
| initParams | webInitParam[] | 配置初始化参数 |
| loadOnStartup | int | 指定servlet的加载顺序默认不配置或数值为负数时表示客户端第一次请求Servlet时再加载0或正数表示启动应用就加载正数情况下数值越小加载该Servlet的优先级越高 |
例如:
```java
@WebServlet(value = "/login")
public class LoginServlet implements Servlet {
//code
}
```
## Servlet的生命周期
当客户端首次发送第一次请求后,由容器(web服务器(tomcat))去解析请求根据请求找到对应的servlet判断该类的对象是否存在不存在则创建servlet实例调取init()方法进行初始化操作初始化完成后调取service()方法由service()判断客户端的请求方式如果是get则执行doGet()如果是post则执行doPost()。处理方法完成后,作出响应结果给客户端。单次请求处理完毕。
当用户发送第二次以后的请求时会判断对象是否存在但是不再执行init()而直接执行service方法调取doGet()/doPost()方法。
当服务器关闭时调取destroy()方法进行销毁。
![](https://i.loli.net/2020/11/26/5sKVlqR1SDomOpF.png)
## Servlet接收/响应请求
客户端发送数据给服务器端的请求方式:
| 请求方式 | 请求类型 | 举例 |
| ------------------ | ------------ | ----------------------------------------------- |
| 通过form表单 | get/post提交 | < form action="请求" method="get/post">< /form> |
| 通过a标签发送数据 | get提交 | < a href = "请求">< /a> |
| 通过地址栏直接拼接 | get请求 | url/请求?key=value&key=value |
| js提交数据 | get请求 | location.href=“目标请求?key=value&key=value” |
> **get/post请求的比较**
>
> 1. 地址栏呈现
>
> * GET请求请求的数据会附加在URL之后以`?`分割URL和传输数据多个参数用`&`连接。
> * POST请求POST请求会把请求的数据放置在HTTP请求包的包体中。
>
> 因此GET请求的数据会暴露在地址栏中而POST请求则不会。
>
> 2. 传输数据的大小
>
> * 在HTTP规范中没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中对于GET特定的浏览器和服务器对URL的长度有限制。因此在使用GET请求时传输数据会受到URL长度的限制。
> * 对于POST由于不是URL传值理论上是不会受限制的但是实际上各个服务器会规定对POST提交数据大小进行限制Apache、IIS都有各自的配置。
>
> 3. 安全性
>
> POST的安全性比GET的高。比如在进行登录操作通过GET请求用户名和密码都会暴露再URL上因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因此时的用户名和密码就很容易被他人拿到。除此之外GET请求提交的数据还可能会造成Cross-site request frogery攻击
HttpServletRequest和HttpServletResponse对象中分别封装了当前的Http请求和响应它们中都有一些方法来处理请求和响应。
HttpServletRequest类常用方法
| 修饰 | 方法名 | 描述 |
| ----------------- | ------------------------------------ | ------------------------------------------------------------ |
| String | getParameter(String name) | 根据表单组件名称获取提交数据返回值是String服务器在接收数据时使用字符串统一接收 |
| String[] | getParameterValues(String name) | 获取表单组件对应多个值时的请求数据 |
| void | setCharacterEncoding(String charset) | 指定每个请求的编码(针对post请求才起作用) |
| RequestDispatcher | getRequestDispatcher(String path) | **转发**,返回一个RequestDispatcher对象该对象的forward( )方法用于转发请求 |
| Session | getSession() | 取得当前会话的Session对象 |
| void | setAttribute(“key”,value) | 存值 |
| void | getAttribute(“key”) | 取值,需要向下转型 |
HttpServletResponse类常用方法
| 修饰 | 方法名 | 描述 |
| ----------- | ------------------------- | ------------------------------------------------------------ |
| void | addCookie(Cookie var1) | 给这个响应添加一个cookie |
| void | sendRedirect(String var1) | **重定向**,发送一条响应码,将浏览器跳转到指定的位置 |
| PrintWriter | getWriter() | 获得字符流通过字符流的write(String s)方法可以将字符串设置到response 缓冲区中随后Tomcat会将response缓冲区中的内容组装成Http响应返回给浏览器端可以返回html/js代码等 |
| void | setContentType() | 设置响应内容的类型 |
> **重定向与转发的区别**
>
> 转发:`httpServletRequest.getRequestDispatcher("目标地址").forward(传递参数)`
>
> 重定向:`httpServletResponse.sendRedirect("目标地址")`
>
> 相同点:都用来跳转页面
>
> 不同点:
>
> * 重定向时地址栏会改变request中存储的数据会丢失。转发时地址栏显示的是请求页面的地址request数据可以保存。
>
> * 转发属于一次请求一次响应,重定向属于两次请求(地址栏修改了两次)两次响应。
>
> ![](https://i.loli.net/2020/11/26/qinVUdSPcCf4uvb.png)
## 会话Session和Cookie
会话的概念:从打开浏览器到关闭浏览器,期间访问服务器就称为一次会话
会话跟踪是Web程序中常用的技术用来跟踪用户的整个会话。保持对用户会话期间的数据管理。常用的会话跟踪技术是Cookie与Session。
* Cookie通过在客户端记录信息确定用户身份
* Session通过在服务器端记录信息确定用户身份。
### Session
**session会话的数据可以在多个页面中共享,即使重定向页面,数据不会丢失**
**Session常用方法**
| 修饰 | 方法名 | 描述 |
| ----------- | ------------------------------------- | ------------------------------------------------------------ |
| void | setAttribute(String key,Object value) | 以key/value的形式保存对象值,将数据存储在服务器端 |
| Object | getAttribute(String key) | 通过key获取对象值 |
| Enumeration | getAttributeNames() | 返回Session中存在的属性名(key) |
| long | getLastAccessedTime() | 返回Session的最后活跃时间。 |
| long | getCreationTime() | 返回Session的创建日期。返回类型为long常被转化为Date类型例如Date createTime = new Date(session.get CreationTime()) |
| void | invalidate() | 设置session对象失效 |
| String | getId() | **获取sessionid,当第一次登录成功后session会产生一个唯一的id**浏览器之后访时如果发现id值还是之前id那么说明 当前访问的属于同一个会话 |
| void | setMaxInactiveInterval(int interval) | 设定session的有效时间单位为s秒默认的有效时间:30分钟 |
| int | getMaxInactiveInterval() | 获取session的有效时间(以秒为单位) |
| boolean | isNew() | 返回该Session是否是新创建的 |
| void | removeAttribute(String key) | 从session中删除指定名称(key)所对应的对象 |
**Session的生命周期**
Session保存在服务器端。**为了获得更高的存取速度服务器一般把Session放在内存**里。每个用户都会有一个独立的Session。如果Session内容过于复杂当大量客户访问服务器时可能会导致内存溢出。因此Session里的信息应该尽量精简。
Session在用户第一次访问服务器的时候自动创建。需要注意**只有访问JSP、Servlet等程序时才会创建Session只访问HTML、IMAGE等静态资源并不会创建Session**。如果尚未生成Session也可以用`request.getSession(true)`强制生成Session。
Session生成后只要用户继续访问服务器就会更新Session的最后访问时间并维护该Session。用户每访问服务器一次无论是否读写Session服务器都认为该用户的Session“活跃active”了一次。
由于会有越来越多的用户访问服务器因此Session也会越来越多。为防止内存溢出服务器会把长时间内没有活跃的Session从内存删除。这个时间就是**Session的超时时间**。如果超过了超时时间没访问过服务器Session就自动失效了。
Session的超时时间为`maxInactiveInterval`属性,可以通过对应的`getMaxInactiveInterval()`获取,通过`setMaxInactiveInterval(long interval)`修改。Session的超时时间也可以在web.xml中修改。另外通过调用Session的`invalidate()`方法可以使Session失效。
```xml
<session-config>
<session-timeout>30</session-timeout> //30分钟
</session-config>
```
### Cookie
Cookie是客户端(一般指浏览器)请求服务器后,服务器发给客户端的一个辨认标识,保存在客户端,当客户端再次向服务器发送请求时,会携带着这个辨认标识,服务器就可以通过这个标识来识别客户端的身份或状态等。
**Cookie的设置和获取**
通过HttpServletResponse.addCookie的方式设置Cookie
```java
Cookie cookie = new Cookie("jieguo","true");
response.addCookie(cookie);
```
服务端获取客户端携带的cookie通过HttpServletRequest获取
```java
Cookie[] cookies = request.getCookies();
if(cookies != null)
for(Cookie c : cookies){
String name = c.getName();//获取Cookie名称
if("jieguo".equals(name)){
String value = c.getValue();//获取Cookie的值
bool = Boolean.valueOf(value);//将值转为Boolean类型
}
}
}
```
**删除Cookie**
通过设置同名Cookie的最大存活时间为0删除Cookie是指使浏览器不再保存Cookie使Cookie立即失效
举例使name为username的Cookie立即失效
```java
//1.创建一个name为username的Cookie
Cookie cookie = new Cookie("username", "aaa");
//2.设置Cookie的有效时间为0
cookie.setMaxAge(0);//删除cookie的关键
//3.将cookie发送给浏览器来替换同名Cookie
response.addCookie(cookie);
```
**Cookie的有效时间**
Cookie发送给浏览器以后浏览器并不会永久保存也就是到了一定的时间以后浏览器会自动销毁Cookie。
Cookie的默认有效时间为一次会话(一次打开关闭浏览器的过程)我们也可以手动指定Cookie的有效时间
```java
//setMaxAge用来设置Cookie的最大有效时间需要int型的参数代表有效的秒数
cookie.setMaxAge(秒数)
//当参数大于0时会设置为指定的秒数
cookie.setMaxAge(30);
//当参数等于0时,浏览器不会保存Cookie,Cookie立即失效
cookie.setMaxAge(0);
//当参数小于0时和不设置是一样当前会话有效
cookie.setMaxAge(-100);
//设置一个永久有效的Cookie并非永久只是使Cookie的生命很长而已
cookie.setMaxAge(60*60*24*365*10);
```
> **Session和Cookie的区别**
>
> * Cookie数据保存在客户端Session数据保存在服务器端。
> * Session是由应用服务器维持的一个服务器端的存储空间用户在连接服务器时会由服务器生成一个唯一的SessionID用该SessionID 为标识符来存取服务器端的Session存储空间。而SessionID这一数据则是保存到客户端用Cookie保存的用户提交页面时会将这一SessionID提交到服务器端来存取Session数据。这一过程是不用开发人员干预的。所以一旦客户端禁用Cookie那么Session也会失效。
> * Cookies是属于Session对象的一种。但有不同Cookies不会占服务器资源是存在客服端内存或者一个Cookie的文本文件中而Session则会占用服务器资源。所以尽量不要使用Session而使用Cookies。但是我们一般认为Cookie是不可靠的Cookies是保存在本机上的但是其信息的完全可见性且易于本地编辑性往往可以引起很多的安全问题。

204
source/_posts/初识Java.md Normal file
View File

@ -0,0 +1,204 @@
---
title: 初识Java
date: 2020-05-16 19:28:35
tags:
- Java
categories:
- Java基础
---
## java帝国的建立
1972 年C语言诞生 C语言具有贴近硬件运行速度极快效率极高的优点一经诞生就广泛用于操作系统、编译器、数据库、网络系统等的开发。但由于C语言的指针问题和内存管理的问题对新手有一些不太友好。
<!--more-->
1982年C++诞生C++兼容C语言它增加了面向对象的特性在图形领域和游戏方面取得了一些成就。但C++更加复杂。
1995年java诞生它语法有些像C但没有C中的指针和内存管理问题它实现了真正的可移植性编写一次到处运行它也有面向对象的特性有更安全的类型有高质量的类库等优点。
### java的发展
1995年的网页简单而粗糙缺乏互动性。java团队在浏览器中放入了java的运行环境开发了一个图形界面程序(Applet)使得网页变得更美观有互动性。java进入了广大程序员的视线。
1998年java 发布java2版本该版本包含三个方向
Java 2 标准版J2SE 针对桌面端开发
Java 2 移动版J2ME 针对移动端开发
Java 2 企业版J2EE 针对服务器端开发
但是Java SE 和Java ME当时并没有得到很好的发展。反而Java EE得到了很多IT大公司的应用 他们基于Java开发了许多的平台、系统、工具
* 构建工具AntMavenJekins
* 应用服务器TomcatJettyJbossWebsphereweblogic
* Web开发StrutsSpringHibernatemyBatis
* 开发工具EclipseNetbeanintellij ideaJbuilder
* ……
2006年Hadoop的发布让Java进入大数据领域
2008年Android的诞生让Java重新进入了移动端领域并在移动端开发中占据了举足轻重的地位。
之后Java的发展就一发不可收拾占据了服务器端开发的大部分市场一个伟大的帝国诞生了
```tex
拓展:
“三高”问题:高可用,高性能,高并发。
```
## Java的特性和优势
* 简单性
* 面向对象
* 跨平台 可移植性
* 高性能
* 分布式
* 动态性(反射机制)
* 多线程
* 安全性
* 健壮性
## Java 的三大版本
### JavaSE
标准版(桌面程序,控制台开发…)
### JavaME
嵌入式开发(手机,小家电…)
该版本几乎已经没有人用了
### JavaEE
企业级开发web端服务器开发…
## JDK、JRE、JVM
JDKJava Development Kit称为Java开发包或者Java开发者工具是一个编写Java的Applet小程序和应用程序的开发环境。JDK是整个Java的核心包括了`Java运行环境(JRE)`,一些`Java工具`和`Java的核心类库(Java API)`。
JREJava Runtime Environment。JRE是个运行环境JDK是个开发环境。因此写Java程序时需要JDK而运行Java程序时就需要JRE。而JDK中已经包含了JRE因此只要安装了JDK就可以编辑Java程序也可以正常运行Java程序。
JVMJava Virtual Machine
![](https://i.loli.net/2020/05/09/h5MHDELCjmzKvcY.png)
## JDK的安装
https://www.oracle.com/java/technologies/javase-jdk8-downloads.html
去上面网址下载对应的版本
下载后双击安装,记住安装的路径
**配置环境变量**
右键点击此电脑,打开属性,找到高级系统设置->环境变量->系统变量
1. 新建一个变量JAVA_HOME值为jdk安装的路径
![](https://i.loli.net/2020/05/09/dF2PvYc5eJ8H9nD.png)
2. 配置Path变量找到系统变量中的Path变量点击编辑新建两个值分别为`%JAVA_HOME%\bin``%JAVA_HOME%\jre\bin`
![](https://i.loli.net/2020/05/09/uaRCMe71En3XG9V.png)
配置好环境变量之后打开cmd(终端),输入
```bash
java -version
```
出现下图效果说明JDK安装配置成功
![](https://i.loli.net/2020/05/09/hTROlwQ7uWEyVaJ.png)
## 第一个程序
**HelloWorld**
步骤:
1. 新建一个文件夹,存放代码
2. 新建一个Java文件(Hello.java)
3. 编写代码
```java
public class Hello{
public static void main(String[] args){
System.out.print("Hello,World!");
}
}
```
4. 编译 ,打开终端,输入命令
```bash
javac -Hello.java
```
编译完成后生成一个Hello.class文件再输入运行命令
```bash
java Hello
```
就能看到终端中打印出了 `Hello,World!`
![](https://i.loli.net/2020/05/09/oLXTjy8ECYeFV25.png)
**可能遇到的问题**
* 每个单词的大小写不能出现问题,**Java对大小写敏感**
* 文件名 和 类名必须保持一致,并且首字母大写
* 符号要用英状态下的符号
## Java程序运行机制
### 编译型与解释型
我们知道计算机是无法理解现在的高级语言程序的计算机只能理解机器语言也就是可以通过CPU进行分析和执行的指令集。而要想让计算机能够运行我们写的高级语言程序就需要一个系统软件来实现它就是**`语言处理程序`**,也称为**`编译程序`**,它可以将我们写的高级语言程序,翻译成计算机可执行的**`机器语言`**。而这个翻译的方式就分为**`编译型`**和**`解释性`**两种。
**`编译型:`**是有一个负责翻译的程序来对我们的源代码进行转换,生成相对应的可执行代码(机器码),这个过程就被称为编译,而来编译的程序也就被称为编译器,也就是说我们写一个程序代码在源文件当中,通常经过编译以后生成一个可执行文件,这样我们就可以直接运行了。
**`解释型:`**在程序运行的前一刻,还只有源程序没有可执行程序,而当执行时每执行到源程序的某一条指令,则会有有一个称为解释程序的外壳程序将源代码转换成二进制代码以供执行,也就是说一边解释 一边执行 ,所以解释型程序是离不开解释程序的。
从上面我们可以看出,编译型和解释型的关键区别就在于这个翻译的时机不同。解释型语言在运行程序的时候才翻译,每执行一次,要翻译一次,效率较低。编译型就是直接编译成机器可以执行的格式,只翻译一次。
编译型和解释型各有优缺点
优点:
解释型:可移植性好,只要有运行相应需要的解释环境,可以在不用的操作系统上运行,修改调试也非常方便
编译型:相比解释执行编译执行效率高,占用资源小,适合复杂程序
缺点:
解释型:一句一句执行解释,浪费计算机资源,效率低
编译型:兼容性差,编译型程序虽然源代码也可以移植,但前提是必须针对不同的系统分别进行编译.
### Java程序运行机制
**Java这个语言有些特殊它既是编译型的又是解释型的**
说Java是编译型的是因为所有的Java代码都是要编译的.java不经过编译就什么用都没有。
说Java是解释型的是因为java代码编译后不能直接运行它是解释运行在JVM上的所以它是解释运行的那也就算是解释型的了。
但是现在的JVM为了效率都有一些JIT优化。它又会把.class的二进制代码编译为本地的代码直接运行所以又是编译的。像C、C++ 他们经过一次编译之后直接可以编译成操作系统了解的类型,可以直接执行的 所以他们是编译型的语言。没有经过第二次的处理 而Java不一样他首先由编译器编译成.class类型的文件这个是Java自己类型的文件 ,然后再通过虚拟机(JVM)从.class文件中读一行解释执行一行所以他是解释型的语言而由于Java对于多种不同的操作系统有不同的JVM所以 Java实现了真正意义上的跨平台
观看下面两张图 了解一下Java的虚拟机机制
> 1.java语言的编译-->解释--->执行过程
>
> ![java语言的编译-->解释--->执行过程](https://i.loli.net/2020/05/10/HtRmwf4LBIr1qPS.jpg)
![java虚拟机JVM](https://i.loli.net/2020/05/10/ITZEnaNuweHiflQ.jpg)
> 如果严格按照定义来说Java应该是解释型语言因为*.java程序在编译之后被编译为\*.class文件并不是机器码依然不能被计算机直接运行。\*.class文件是在JVM中被解释运行的。

View File

@ -0,0 +1,588 @@
---
title: 枚举、注解和反射
date: 2020-11-16 19:24:54
tags:
- Java
categories:
- Java基础
---
## 枚举
### 简介
JDK1.5引入了新的类型——枚举。
在JDK1.5 之前,我们定义常量都是: public static fianl.... 。很难管理。
枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。用于定义有限数量的一组同类常量,例如:
<!-- more -->
```tex
错误级别:
低、中、高、急
一年的四季:
春、夏、秋、冬
商品的类型:
美妆、手机、电脑、男装、女装...
```
在枚举类型中定义的常量是该枚举类型的**实例**。
### 定义格式
```java
权限修饰符 enum 枚举名称 {
实例1,实例2实例3,...实例n;
}
```
```java
public enum Level {
LOW(1), MEDIUM(2), HIGH(3), URGENT(4);
private int levelValue;
private Level(int levelValue) {
this.levelValue = levelValue;
}
public int getLevelValue() {
return levelValue;
}
}
```
```java
public enum Level { //这样的方式更常用,通过字面意思就能理解枚举中常量的含义
LOW, MEDIUM, HIGH, URGENT;
}
```
### 枚举类的主要方法
Enum<font color =red>抽象类</font>常见方法
Enum是所有Java语言枚举类型的公共基本类以下是它的常见方法
| 变量和类型 | 方法 | 描述 |
| :---------------------------: | :---------------------------------------: | :----------------------------------------------------------: |
| `protected Object` | `clone()` | 抛出CloneNotSupportedException。 |
| `int` | `compareTo(E o)` | 将此枚举与指定的对象进行比较。 |
| `boolean` | `equals(Object other)` | 如果指定的对象等于此枚举常量则返回true。 |
| `Class<?>` | `getDeclaringClass()` | 返回与此枚举常量的枚举类型对应的Class对象。 |
| `int` | `hashCode()` | 返回此枚举常量的哈希码。 |
| `String` | `name()` | 返回此枚举常量的名称,与其枚举声明中声明的完全相同。 |
| `int` | `ordinal()` | 返回此枚举常量的序数(它在枚举声明中的位置,其中初始常量的序数为零)。 |
| `String` | `toString()` | 返回声明中包含的此枚举常量的名称。 |
| `static<T extends Enum<T>> T` | `valueOf(Class<T> enumType, String name)` | 返回具有指定名称的指定枚举类型的枚举常量。 |
> 以上方法中只有toString()方法可以被重写
### 实现接口的枚举类
所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
每个枚举对象,都可以实现自己的抽象方法
```java
public interface LShow{
void show();
}
public enum Level implements LShow{
LOW{
@Override
public void show(){
//...
}
},MEDIUM{
@Override
public void show(){
//...
}
},HIGH{
@Override
public void show(){
//...
}
};
}
```
### 注意事项
* 一旦定义了枚举,最好不要妄图修改里面的值,除非修改是必要的。
* 枚举类默认继承的是java.lang.Enum类而不是Object类
* 枚举类不能有子类因为其枚举类默认被final修饰
* 只能有private构造方法
* switch中使用枚举时直接使用常量名不用携带类名
* 不能定义name属性因为自带name属性
* 不要为枚举类中的属性提供set方法不符合枚举最初设计初衷。
## 注解
### 简介
Java 注解Annotation又称 Java 标注,是 JDK5.0 引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和注释不同Java 标注可以通过反射获取标
注内容。在编译器生成类文件时标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行
时可以获取到标注内容 。 当然它也支持自定义 Java 标注。
主要用于:编译格式检查、反射中解析、生成帮助文档、跟踪代码依赖等
### 内置注解
* `@Override ` 重写
* 定义在java.lang.Override
* `@Deprecated`:废弃
* 定义在java.lang.Deprecated
* `@SafeVarargs`
* Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
* `@FunctionalInterface` 函数式接口
* Java 8 开始支持,标识一个匿名函数或函数式接口。
* `@Repeatable`:标识某注解可以在同一个声明上使用多次
* Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
* `SuppressWarnings()` 抑制编译时的警告信息。
* 定义在java.lang.SuppressWarnings
* 三种使用方式
* `@SuppressWarnings("unchecked")` 抑制单类型的警告
* `@SuppressWarnings("unchecked","rawtypes")`:抑制多类型的警告
* `@SuppressWarnings("all") `:抑制所有类型的警告
* 参数列表:
* | 关键字 | 用途 |
| ------------------------ | -------------------------------------------------- |
| all | 抑制所有警告 |
| boxing | 抑制装箱、拆箱操作时候的警告 |
| cast | 抑制映射相关的警告 |
| dep-ann | 抑制启用注释的警告 |
| deprecation | 抑制过期方法警告 |
| fallthrough | 抑制确在switch中缺失breaks的警告 |
| finally | 抑制finally模块没有返回的警告 |
| hiding | 抑制相对于隐藏变量的局部变量的警告 |
| incomplete-switch | 忽略没有完整的switch语句 |
| nls | 忽略非nls格式的字符 |
| null | 忽略对null的操作 |
| rawtypes | 使用generics时忽略没有指定相应的类型 |
| restriction | 抑制禁止使用劝阻或禁止引用的警告 |
| serial | 忽略在serializable类中没有声明serialVersionUID变量 |
| static-access | 抑制不正确的静态访问方式警告 |
| synthetic-access | 抑制子类没有按最优方法访问内部类的警告 |
| unchecked | 抑制没有进行类型检查操作的警告 |
| unqualified-field-access | 抑制没有权限访问的域的警告 |
| unused | 抑制没被使用过的代码的警告 |
### 元注解
元注解就是**作用在其他注解**的注解。有下面几种:
* `@Retention`- 标识这个注解怎么保存是只在代码中还是编入class文件中或者是在运行时可以通过反射访问。
* `@Documented` - 标记这些注解是否包含在用户文档中。
* `@Target` - 标记这个注解应该是哪种 Java 成员。
* `@Inherited` - 标记这个注解是自动继承的
* 子类会继承父类使用的注解中被`@Inherited`修饰的注解
2. 接口继承关系中,子接口不会继承父接口中的任何注解,不管父接口中使用的注解有没有
被`@Inherited`修饰
3. 类实现接口时不会继承任何接口中定义的注解
### 自定义注解
#### 注解架构
![](https://i.loli.net/2020/10/26/e5pqFSIxH2NdlUn.png)
* **`Annotation`与`RetentionPolicy` 、`ElementType` 。**
每 1 个 `Annotation` 对象,都会有**唯一的 `RetentionPolicy` 属性,有 1~n个`ElementType`属性**。
* **`ElementType`(注解的用途类型)**
"每 1 个 `Annotation`" 都与 "1n 个 `ElementType`" 关联。当 `Annotation` 与某个 `ElementType` 关联时,就意味着:`Annotation`有了某种用途。例如,若一个 `Annotation` 对象是 `METHOD` 类型,则该`Annotation` 只能用来修饰方法。
```java
package java.lang.annotation;
public enum ElementType {
TYPE, // 类、接口(包括注释类型)或枚举声明
FIELD, // 字段声明(包括枚举常量)
METHOD, // 方法声明
PARAMETER, // 参数声明
CONSTRUCTOR, // 构造方法声明
LOCAL_VARIABLE, // 局部变量声明
ANNOTATION_TYPE,// 注释类型声明
PACKAGE // 包声明
}
```
* **`RetentionPolicy`(注解作用域策略)**。
"每 1 个 `Annotation`" 都与 "1 个 `RetentionPolicy`" 关联。
* 若 `Annotation` 的类型为 `SOURCE`,则意味着:`Annotation` 仅存在于编译器处理期间,编译器处理完之后,该`Annotation` 就没用了。 例如,"`@Override`" 标志就是一个 `Annotation`。当它修饰一个方法的时候,就意味着该方法覆盖父类的方法;并且在编译期间会进行语法检查!编译器处理完后,"`@Override`" 就没有任何作用了。
* 若 `Annotation` 的类型为 `CLASS`,则意味着:编译器将 `Annotation` 存储于类对应的 `.class`文件中,它是 `Annotation` 的默认行为。
* 若 `Annotation` 的类型为 `RUNTIME`,则意味着:编译器将 `Annotation` 存储于 `.class` 文件中并且可由JVM读入。
```java
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, //Annotation信息仅存在于编译器处理期间编译器处理完之后就没有该Annotation信息了
CLASS, //编译器将Annotation存储于类对应的.class文件中。默认行为
RUNTIME //编译器将Annotation存储于class文件中并且可由JVM读入
}
```
#### 定义格式
```java
@interface 自定义注解名{}
```
> 注意事项
>
> 1. 定义的注解自动继承了java.lang.annotation.Annotation接口
> 2. **注解中的每一个方法,实际是声明的注解配置参数**
> * 方法的名称就是配置参数的名称
> * 方法的返回值类型,就是配置参数的类型。只能是:基本类型/Class/String/enum
> 3. 可以通过default来声明参数的默认值
> 4. 如果只有一个参数成员一般参数名为value
> 5. 注解元素必须要有值,我们定义注解元素时,经常使用空字符串、 0 作为默认值。
**案例**
```java
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation1 {
参数类型 参数名() default 默认值;
}
```
上面代码的作用是定义一个 `Annotation`,我们可以在代码中通过 "`@MyAnnotation1`" 来使用它。
`@Documented` `@Target``@Retention``@interface` 都是来修饰 `MyAnnotation1` 的。含义:
* `@interface`
使用 `@interface` 定义注解时,意味着它实现了 `java.lang.annotation.Annotation` 接口,即该注解就是`一个Annotation`。
> <font color = red>定义`Annotation` 时,`@interface` 是必须的。</font>
>
> 注意:它和我们通常的 `implemented` 实现接口的方法不同。`Annotation` 接口的实现细节都由编译器完成。通过 `@interface` 定义注解后,该注解不能继承其他的注解或接口。
* `@Documented`
类和方法的 `Annotation` 在缺省情况下是不出现在 `javadoc` 中的。如果使用 `@Documented` 修饰该
`Annotation`,则表示它可以出现在 `javadoc` 中。
> 定义 `Annotation` 时,**`@Documented `可有可无**;若没有定义,则 `Annotation` 不会出现在 `javadoc`中。
* `@Target(ElementType.TYPE)`
`ElementType``Annotation` 的类型属性。而 `@Target` 的作用,就是来指定`Annotation` 的类型属性的。
`@Target(ElementType.TYPE)` 的意思就是指定该 `Annotation` 的类型是 `ElementType.TYPE`。这就意味着,`MyAnnotation1` 是来修饰"类、接口(包括注释类型)或枚举声明"的注解。
> 定义 `Annotation` 时,**`@Target` 可有可无**。若有 `@Target`,则该 `Annotation` 只能用于它所指定的地方;若没有 `@Target`,则该 `Annotation` 可以用于任何地方。
* `@Retention(RetentionPolicy.RUNTIME)`
`RetentionPolicy``Annotation` 的策略属性,而 `@Retention` 的作用,就是指定`Annotation` 的策略属性。
`@Retention(RetentionPolicy.RUNTIME)` 的意思就是指定该 `Annotation` 的策略是
`RetentionPolicy.RUNTIME`。这就意味着,编译器会将该 `Annotation` 信息保留在 `.class `文件中并且能被JVM虚拟机读取。
> 定义 `Annotation` 时,`@Retention `可有可无。若没有 `@Retention`,则默认是
> `RetentionPolicy.CLASS`
## 反射
### 概述
[JAVA反射机制](https://baike.baidu.com/item/JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin)是在运行状态中,获取任意一个类的结构 、 创建对象 、得到方法、执行方法 、属性这种在运行状态动态获取信息以及动态调用对象方法的功能被称为java语言的反射机制。
### 类加载器
Java类加载器Java Classloader是Java运行时环境Java Runtime Environment的一部分负责动态加载Java类到Java虚拟机的内存空间中。
java默认有三种类加载器:`BootstrapClassLoader`、`ExtensionClassLoader`、`App ClassLoader`。
* **BootstrapClassLoader引导启动类加载器**
嵌在JVM内核中的加载器该加载器是用C++语言原生语言写的主要负载加载JAVA_HOME/lib下的类库引导启动类加载器无法被应用程序直接使用。
* **ExtensionClassLoader扩展类加载器**
ExtensionClassLoader是用JAVA编写且它的父类加载器是Bootstrap。
是由sun.misc.Launcher$ExtClassLoader实现的主要加载JAVA_HOME/lib/ext目录中的类库。
* **App ClassLoader应用类加载器**
App ClassLoader是应用程序类加载器负责加载应用程序classpath目录下的所有jar和class文
件。它的父加载器为Ext ClassLoader
![](https://i.loli.net/2020/10/26/TGtjSkCnMwp8qUO.png)
> 类通常是按需加载即第一次使用该类时才加载。由于有了类加载器Java运行时系统不需要知道文件与文件系统。
>
> **委派**
>
> 双亲委派模型:<font color = red>如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成</font>。每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。
> **加载配置文件**
>
> 如果我们的项目下有source文件夹类.class.getClassLoader().getResourceAsStream(文件名)加载的是source文件夹下的文件前提是将文件夹定义为Resources Root
>
> ![image-20201026212548653](https://i.loli.net/2020/10/26/4THGmUu6PEno3qk.png)
>
> ![](https://i.loli.net/2020/10/26/JqeIEhX34APUScv.png)
### 获取类对象
要想了解一个类必须先要获取到该类的字节码文件对象。在Java中每一个字节码文件被加载到内存后都存在一个对应的Class类型的对象
**得到Class的几种方式**
1. 如果在编写代码时, 知道类的名称, 且类已经存在, 可以通过下面代码得到一个类的 类对象
```java
包名.类名.class
```
2. 如果拥有类的对象, 可以通过下面代码得到一个类的类对象
```java
Class 对象.getClass()
```
3. 如果在编写代码时, 知道类的名称 , 可以通过下面代码得到一个类的类对象
```java
Class.forName("包名.类名");
```
上述的三种方式, 在调用时, 如果类在内存中不存在, 则会加载到内存! 如果类已经在内存中存在, 不会重复加载, 而是重复利用!
![](https://i.loli.net/2020/10/26/2X4A53NFvROnwGx.png)
> (一个class文件 在内存中不会存在两个类对象 )
>
> 特殊的类对象
>
> * 基本数据类型的类对象:
> * 基本数据类型.class
> * 包装类.type
> * 基本数据类型包装类对象:
> * 包装类.class
### 获取Constructor
**通过class对象 获取一个类的构造方法**
1. 通过指定的参数类型, 获取指定的单个构造方法
```java
getConstructor(参数类型的class对象数组)
```
例如,构造方法如下:
```java
Person(String name,int age)
```
得到这个构造方法的代码如下:
```java
Constructor c = p.getClass().getConstructor(String.class,int.class);
```
2. 获取构造方法数组
```java
getConstructors();
```
3. 获取所有权限的单个构造方法
```java
getDeclaredConstructor(参数类型的class对象数组)
```
4. 获取所有权限的构造方法数组
```java
getDeclaredConstructors();
```
**Constructor 创建对象**
常用方法:
* `newInstance(Object... para)`
调用这个构造方法, 把对应的对象创建出来
参数: 是一个Object类型可变参数, 传递的参数顺序 必须匹配构造方法中形式参数列表的顺序!
* `setAccessible(boolean flag)`
如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的方法)
![](https://i.loli.net/2020/10/26/OUb4plBsyCr7gX2.png)
### 获取Method
**通过class对象获取一个类的方法**
1. 根据参数列表的类型和方法名, 得到一个方法(public修饰的)
```java
getMethod(String methodName , class... clss)
```
2. 得到一个类的所有方法 (public修饰的)
```java
getMethods()
```
3. 根据参数列表的类型和方法名, 得到一个方法(除继承以外所有的:包含私有,公有, 保护, 默认)
```java
getDeclaredMethod(String methodName , class... clss)
```
4. 得到一个类的所有方法 (除继承以外所有的:包含私有,公有, 保护, 默认)
```java
getDeclaredMethods()
```
**Method 执行方法**
* `invoke(Object o,Object... para)`
参数1. 要调用方法的对象
参数2. 要传递的参数列表
* `getName()`
获取方法的方法名称
* `setAccessible(boolean flag)`
如果flag为true 则{表示忽略访问权限检查 !(可以访问任何权限的方法)
![](https://i.loli.net/2020/10/26/u3T6tlMyavn59Kf.png)
### 获取Field
**通过class对象 获取一个类的属性**
1. 根据属性的名称, 获取一个属性对象 (所有属性)
```java
getDeclaredField(String filedName)
```
2. 获取所有属性(所有权限)
```java
getDeclaredFields()
```
3. 根据属性的名称, 获取一个属性对象 (public属性)
```java
getField(String filedName)
```
4. 获取所有属性 (public)
```java
getFields()
```
**Field 属性的对象类型**
常用方法:
* `get(Object o)`
参数: 要获取属性的对象,获取指定对象的此属性值
* `set(Object o , Object value)`
参数1.要设置属性值的对象参数2. 要设置的值。设置指定对象的属性的值
* `getName()`
获取属性的名称
* `setAccessible(boolean flag)`
如果flag为true 则表示忽略访问权限检查 !(可以访问任何权限的属性)
![](https://i.loli.net/2020/10/26/JzatTMCxEkdjfZw.png)
### 获取注解信息
**获取类/属性/方法的全部注解对象**
```java
Annotation[] annotations = Class/Field/Method.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
```
**根据类型获取类/属性/方法的注解对象**
```
注解类型 对象名 = (注解类型) c.getAnnotation(注解类型.class);
```
![](https://i.loli.net/2020/10/26/ZuIB4gvK5yWfUxD.png)
## 内省
### 简介
内省即基于反射 java所提供的一套应用到JavaBean的API。
> 一个定义在包中的类 拥有无参构造器所有属性私有所有属性提供get/set方法实现了序列化接口。这种类, 我们称其为 bean类。
>
> Java提供了一套java.beans包的api ,对反射的操作,进行了封装!
### Introspector
获取Bean类信息方法:
`BeanInfo getBeanInfo(Class cls)` :通过传入的类信息, 得到这个Bean类的封装对象.
### BeanInfo
常用的方法:
`MethodDescriptor[] getPropertyDescriptors()`:获取bean类的 get/set方法 数组
### MethodDescriptor
常用方法:
`Method getReadMethod()`获取一个get方法
`Method getWriteMethod()`获取一个set方法
<font color = red>有可能返回null 注意加判断!</font>
![image-20201026234226051](https://i.loli.net/2020/10/26/8UqRoVuAdaIewJ6.png)

View File

@ -0,0 +1,937 @@
---
title: 移动端布局
date: 2020-11-16 19:31:49
tags:
- 前端
- flex布局
- 响应式布局
categories:
- 前端
---
## 移动端现状
* 内核
* 当前国产主流手机浏览器内核都是Webkit
* 分辨率:手机分辨率,碎片化太多
* Android480x800, 480x854, 540x960, 720x12801080x1920 等
* iPhone640x960, 640x1136, 750x1334, 1242x2208 等
* 2K、4K等高分辨率
<!-- more -->
在开发过程中Google chrome是主要模拟手机的手段之一步骤
1. 鼠标右键 检查 或 F12 控制器界面方向;
2. 选择 手机模式
3. 选择 手机类型及尺寸;调节适当的显示比例;
4. 点右键 查看 页面元素;
![](https://i.loli.net/2020/11/05/Gkg6KFxR7IHm3ZJ.png)
## viewport(视口)
**定义:**
视口浏览器PC、移动端显示页面内容的屏幕区域不同的屏幕的大小我们看到的区域也是不同的
PC端的页面直接放入手机屏显示不友好可以用viewport来解决
![image-20201105130620315](https://i.loli.net/2020/11/05/s1gtWMJ95GX42j3.png)
![](https://i.loli.net/2020/11/05/Y7wazID9g2hUQGO.png)
HTML宽度默认为980px不是很合适
> 各手机型号尺寸:
>
> | 设备 | 尺寸(英寸) | 开发尺寸px | 物理像素比dpr |
> | -------------------- | ------------ | -------------- | ----------------- |
> | iphone3G | 3.5 | 320*480 | 1.0 |
> | iphone4/4s | 3.5 | 320*480 | 2.0 |
> | iphone5/5s/5c | 4.0 | 320*568 | 2.0 |
> | HTC One M8 | 4.5 | 360*640 | 3.0 |
> | iphone6 | 4.7 | 375*667 | 2.0 |
> | Nexus4 | 4.7 | 384*640 | 2.0 |
> | Nexus5x | 5.2 | 411*731 | 2.6 |
> | iphone6 Plus | 5.5 | 414*736 | 3.0 |
> | Samsung Galaxy Note4 | 5.7 | 480*853 | 3.0 |
> | Sony Xperia Z Ultra | 6.4 | 540*960 | 2.0 |
> | Nexus 7(12) | 7.0 | 600*960 | 1.3 |
> | iPad Mini | 7.9 | 768*1024 | 1.0 |
>
>
那么设置HTML宽度多少为合适呢设置为屏幕的窗口大小应该正好合适
**设置viewport**
meta标签设置
```html
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0,maximum-scale=1.0, minimum-scale=1.0">
```
`width=device-width`改变HTML默认的980px 为 屏幕的宽度;
`user-scalable`: 是否允许用户缩放屏幕 值no(0不允许) yes(1允许)
`initial-scale`初始化缩放比例1.0:不缩放;
`maximum-scale`:用户对页面的最大缩放比例;值:比例
`minimum-scale`:用户对页面的最小缩放比例;值:比例
## 二倍图
**物理像素点**
* 指计算机显示设备中的最小单位,即一个像素点的大小。每一个像素点可以理解为就是屏幕上的一个发光
点。每个点可以发一个颜色,就是我们看到的画面。
* 早期的屏幕,物理像素点都比较大,随着技术的进步,物理像素点会被做的越来越小。
**屏幕分辨率**
* 由物理像素点的个数来衡量,表示屏幕水平和垂直方向的物理像素点的个数。
> 例如iPhone3和iPhone4是同一个屏幕尺寸下比较分辨率
>
> ![](https://i.loli.net/2020/11/05/tmYVi7JlQxLUeup.png)
>
> Retina视网膜屏幕是一种显示技术可以将把更多的物理像素点压缩至一块屏幕里从而达到更高的分辨率并提高屏幕显示的细腻程度。
>
> ![image-20201105133553373](https://i.loli.net/2020/11/05/NfyYevr6w3DQa1q.png)
**图片分辨率**
假设有200*200分辨率的图片展示在宽度分别是320iphone3、640(iphone4)分辨率的手机上,展示
的效果如下:
![image-20201105133722991](https://i.loli.net/2020/11/05/AKrpNHldgYZSI6F.png)
可以看出不同的屏幕下显示的图片大小是不一样的物理像素点的宽度大小为10.5物理像素点的数量3201 x 200=200长度、640(0.5 x 400=200长度都设为是200长度才能保证显示的大小一样这时320的屏幕是200像素点而640的屏幕是400个像素点。
在移动端我们可以通过设置CSS样式宽高200px后会自动保证每个屏幕显示元素大小一样它会自动算出不同屏幕下背后需要提供物理像素点需要多少个。
**二倍图**
像针对640分辨率手机屏iPhone4要求设计给400*400图对应我们CSS设置200px,有二倍的关系:
命名:
* xxxxx@2x.png二倍图
* xxxxx@3x.png三倍图
## 移动端常见布局
了解常见布局不同,针对业务需求选择不同的方案;实际开发过程中,都是混合使用,没有哪一种是绝对的
单独使用。
常见布局包括以下几种方式
* 单独制作移动端页面
* 流式布局 (百分比布局)
* flex弹性布局 (强列推荐)
* less+rem+媒体查询布局
* 混合布局
* 响应式页面兼容移动端
* 媒体查询
* bootstrap
比较:
* 单独制作流式、flex、rem布局、专门针对各种手机屏幕进行开发。例如淘宝、京东、苏宁手机端都是单独制作的
* 响应式可兼容PC 移动端一个页面多个端适配显示制作起来要考虑到兼容性的样式。例如三星电子官网www.samsung.com/cn/ 就是响应式布局
### 流式布局
看下面代码,左右两部分以百分比来定义宽度,这样无论屏幕如何变化都可以保证效果
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{margin: 0;padding: 0;}
.op{
width: 100%;
border: 1px solid red;
overflow: hidden;
}
.op>div{
float: left;
}
.left{
width: 40%;
height: 200px;
background: blue;
}
.right{
width: 60%;
height: 200px;
background: pink;
}
</style>
</head>
<body>
<div class="op">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
</html>
```
### flex布局
参考[Flex 布局教程:语法篇](https://ruanyifeng.com/blog/2015/07/flex-grammar.html)
#### flex介绍
布局的传统解决方案,基于[盒状模型](https://developer.mozilla.org/en-US/docs/Web/CSS/box_model),依赖 [`display`](https://developer.mozilla.org/en-US/docs/Web/CSS/display) 属性 + [`position`](https://developer.mozilla.org/en-US/docs/Web/CSS/position)属性 + [`float`](https://developer.mozilla.org/en-US/docs/Web/CSS/float)属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
2009年W3C 提出了一种新的方案----Flex 布局,可以简便、完整、响应式地实现各种页面布局。目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能。
Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
**传统布局与flex布局比较**
* 传统布局:
* 兼容性好、布局繁琐、浮动(清除浮动)
* 有局限性不能在移动端很好的布局
* flex布局
* 操作方便,布局极其简单,移动端使用比较广泛
* PC端浏览器支持情况比较差
> 如果是PC端页面布局采用传统方式如果是移动端或者是不考虑兼容的PC端则采用flex布局
**flex布局特点**
* 任何一个容器标签都可以指定使用 flex 布局。
* <font color = red>当为父标签设为 flex 布局以后,子元素的 `float`、`clear` 和 `vertical-align` 属性将失效。</font>
* 使用思想上和传统盒子完全不同,不要再想子元素是块级元素、行内元素,
* flex通过行和列的思路来控制布局
**基本概念:**
采用 flex 布局的元素,称为 flex 容器flex container父级简称"**容器**"。它的所有子元素自动成为容器成员,称为 flex 项目flex item简称"**项目**"。
![](https://i.loli.net/2020/11/05/Oznr9KpjHYfoLe8.png)
**语法使用:**
任何一个容器都可以指定为 Flex 布局。
> ```css
> .box{
> display: flex;
> }
> ```
行内元素也可以使用 Flex 布局。
> ```css
> .box{
> display: inline-flex;
> }
> ```
Webkit 内核的浏览器,必须加上`-webkit`前缀。
> ```css
> .box{
> display: -webkit-flex; /* Safari */
> display: flex;
> }
> ```
#### 容器属性
容器属性有以下6个
- `flex-direction`
- `flex-wrap`
- `flex-flow`
- `justify-content`
- `align-items`
- `align-content`
##### flex-direction属性
`flex-direction`属性决定主轴的方向(即项目的排列方向)。元素默认按照确认的主轴方向进行排布。
```css
flex-direction:row | row-reverse | column | column-reverse;
```
它有4个值
| 属性值 | 说明 |
| :--------------- | :------------------ |
| `row` (默认值) | 水平方向 ,从左到右 |
| `row-reverse` | 水平方向,从右到左 |
| `column` | 垂直方向,从上到下 |
| `column-reverse` | 垂直方向,从下到上 |
##### flex-wrap属性
默认情况下,项目都排在一条线(又称"轴线")上。`flex-wrap`属性定义,如果一条轴线排不下,如何换行。
```css
flex-wrap:nowrap | warp | wrap-reverse;
```
它有3个值
| 属性值 | 说明 |
| :--------------- | :----------------------------------------------------------- |
| `nowarp`(默认值) | 不换行;子项目加起来的宽度超过父级的宽度时,子项宽度会被缩小,宽度只是不生效,必须设置 |
| `warp` | 换行,子项的总宽加起来超过父级宽度,就会换行,第一行在上方 |
| `warp-reverse` | 换行,子项的总宽加起来超过父级宽度,就会换行,第一行在下方 |
##### flex-flow属性
`flex-flow`属性是`flex-direction`属性和`flex-wrap`属性的简写形式,默认值为`row nowrap`。
```css
flex-flow: <flex-direction> || <flex-wrap>;
```
##### justify-content属性
`justify-content`属性定义了项目在主轴上的对齐方式类似word里的左对齐右对齐居中对齐分散对齐
```css
justify-content: flex-start | flex-end | center | space-between | space-around;
```
它有5个值
| 属性值 | 说明 |
| :------------------- | :----------------------------------------------------------- |
| `flex-start`(默认值) | 从头部开始 排列如果主轴是x轴则从左到右左对齐 |
| `flex-end` | 从尾部开始排列 |
| `center` | 在主轴居中对齐如果主轴是x轴 水平居中) |
| `space-around` | 每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。 |
| `space-between` | 两端对齐,项目之间的间隔都相等。 |
![image-20201105165428118](https://i.loli.net/2020/11/05/TVsbDKdaExAP8f4.png)
##### align-items属性
`align-items`属性是控制子项单行在侧轴交叉轴默认是y轴上的对齐方式在子项为单项单行的时候使用整体一行元素看成整体设置在侧轴上的对齐方式。
```css
align-items: flex-start | flex-end | center | baseline | stretch;
```
它有5个值
| 属性值 | 说明 |
| :---------------- | :--------------------------------------------------- |
| `flex-start` | 交叉轴的起点对齐(如果是y轴 ,从上到下) |
| `flex-end` | 交叉轴的终点对齐 |
| `center` | 交叉轴的中点对齐。 |
| `stretch`(默认值) | 如果项目未设置高度或设为auto将占满整个容器的高度。 |
| `baseline` | 项目的第一行文字的基线对齐。 |
![](https://i.loli.net/2020/11/05/Pb8shxufpnevYMS.png)
##### align-content属性
`align-content`属性设置项目在侧轴的排列方式 ,只能用于子项出现换行或者多行的情况,如果项目只有一根轴线(一行),该属性不起作用。
```css
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
```
它有6个值
| 属性值 | 说明 |
| :---------------- | :----------------------------------------------------------- |
| `flex-start` | 从侧轴头部开始排列 |
| `flex-end` | 从侧轴尾部开始排列 |
| `center` | 在侧轴中间显示 |
| `stretch`(默认值) | 项目高度平分容器高度 |
| `space-between` | 与侧轴两端对齐,轴线之间的间隔平均分布。 |
| `space-arond` | 每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。 |
![image-20201105171729060](https://i.loli.net/2020/11/05/NvrsDGHJ3mp6WM9.png)
#### 项目属性
项目属性有以下6个
- `order`
- `flex-grow`
- `flex-shrink`
- `flex-basis`
- `flex`
- `align-self`
##### order属性
![](https://i.loli.net/2020/11/05/EZfINrvdcjOiazR.png)
##### flex-grow属性
![image-20201105172534642](https://i.loli.net/2020/11/05/dmEyo3HPGRc9WJK.png)
##### flex-shrink属性
![](https://i.loli.net/2020/11/05/QTybV43Cfz62JLo.png)
##### flex-basis属性
![](https://i.loli.net/2020/11/05/PIBMRicrzHqlyn2.png)
##### flex属性
`flex`属性是`flex-grow`, `flex-shrink``flex-basis`的简写,默认值为`0 1 auto`。后两个属性可选。
```css
.item {
flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]
}
```
该属性有两个快捷值:`auto` (`1 1 auto`) 和 `none` (`0 0 auto`)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
##### align-self属性
`align-self`属性允许单个项目有与其他项目不一样的对齐方式,可覆盖`align-items`属性。默认值为`auto`,表示继承父元素的`align-items`属性,如果没有父元素,则等同于`stretch`。
```css
.item {
align-self: auto | flex-start | flex-end | center | baseline | stretch;
}
```
除了auto其他5个属性值的含义与`align-items`属性完全一样。
### 移动端适配
#### 媒体查询
> 媒体查询可以感受到屏幕的变化;可以根据屏幕不同的宽,从而获得不同的样式,然后实现不同的样式显示。
>
> 1. CSS3 新语法,是一个查询屏幕的过程,通过查询当前屏幕尺寸属于哪个范围,从而有哪个范围的样式生效;
>
> 2. 感受屏幕变化,屏幕变化就是宽度的变化,通过预设置,当屏幕到了我已经预设置的变化的范围,就会把我提前设置好的样式进行生效;
**语法**CSS样式如下
```css
/*
mediatype 查询类型:
-----------------
all 所有设备
print 用于打印机和打印预览
screen 用于电脑屏幕,平板电脑,智能手机等。
条件:
----
and 并且 not 不满足 only 仅仅满足
media feature 查询条件:
----------------------
width,min-with,max-width
*/
@media mediatype and|not|only (media feature) {
CSS-Code;
}
```
**例子:**如果文档宽度小于 500 像素则修改背景颜色(background-color)
```css
/* min-width/max-width最小界值最大界值查询条件包含等于号*/
@media screen and (max-width:499px) {
body {
background-color: red;
}
}
```
#### rem
> rem是一个相对单位类似于em
>
> 不同的是rem的基准是相对于html元素的字体大小em是父元素字体大小。
rem让一些不能等比自适应的元素达到当设备尺寸发生改变的时候等比例适配当前设备。
rem单位可以控制整个页面所有元素有关PX类宽、高、padding、margin、top...)只要是你设置数值的地方都可以实现控制;
根(root): 1 rem代表HTML的font-size大小
```css
/* 1.根html 为 10px */
html {
font-size: 10px;
}
/* 2.此时 div 的宽就是 150px */
div {
width: 15rem;
}
```
**rem应用**
使用媒体查询根据不同设备按比例设置html的字体大小然后页面元素使用rem做尺寸单位当html字体大小变化元素尺寸也会发生变化从而达到等比缩放的适配。
```css
@media screen and (min-width: 320px) {
html {
font-size: 20px;
}
}
@media screen and (min-width: 640px) {
html {
font-size: 40px;
}
}
/*在屏幕宽度为320px-639px的设备上div的宽高就都是20px;
在屏幕宽度大与等于640px的设备上div的宽高就都是40px;*/
div {
width:1rem;
height:1rem;
}
```
#### less
* less : 让你写更少的代码,实现相同的效果;
* less :是一门 CSS 扩展语言它扩展了CSS的动态特性。 CSS 预处理语言。
* 常见的CSS预处理器Sass、Less、Stylus 。
* Less中文网址http://lesscss.cn/
**less安装**
sublime安装less和less2Css插件
https://blog.csdn.net/redase/article/details/83998172
vscode安装less插件
* 在扩展:商店中搜 Easy Less安装即可
测试:写一个.less文件保存就会在当前目录生成一个对应的.css文件
![image-20201105205211449](https://i.loli.net/2020/11/05/SCPpKOIl3Qy4soZ.png)
**less变量**
变量是指没有固定的值可以改变的。我们CSS中的一些颜色和数值等经常使用可以设置为变量语法
```less
//@变量名:值;
@bg:#333;
.box_1 {
background-color: @bg;
}
.box_2 {
background-color: @bg;
}
```
变量命名规则:
* 必须有@为前缀
* 不能包含特殊字符~=+、不能以数字开头
* 大小写敏感区分;
**less嵌套**
类似HTML一样写less结构语法
```css
/* css 写法 */
#header .logo {
width: 300px;
}
/* less 写法 */
#header {
.logo {
width: 300px;
}
}
```
交集|伪类|伪元素选择器,语法:
```css
/* css写法 */
a:hover{
color:red;
}
/* less写法 */
a{
&:hover{
color:red;
}
}
```
**less运算**
任何数字、颜色或者变量都可以参与运算Less提供了加+)、减(-)、乘(*)、除(/)算术运算。
```less
// 数字
width: 200px - 50;
// 颜色
background-color: #666 - #222;
// 注意:运算符中间左右有个空格隔开
```
运算后的单位选择:
* 如果两个值之间只有一个值有单位,则运算结果就取该单位
* 对于两个不同的单位的值之间的运算,运算结果的值取第一个值的单位
> 更多less的用法可以访问less的文档
>
> 1. http://lesscss.cn/
>
> 2. https://less.bootcss.com/
#### 两种移动端适配方案
##### 方案一 rem+媒体查询+less
上面已经说明过了
使用媒体查询根据不同设备按比例设置html的字体大小然后页面元素使用rem做尺寸单位当html字体大小变化元素尺寸也会发生变化从而达到等比缩放的适配。
大概步骤就是:
1. 准备各个档位下的rem 提前准备好各个档位下的HTML 的font-size大小
2. 拿到当前尺寸的1rem代表多少px
3. 计算比例把页面刚才所有的元素的PX值替换为rem,可通过less来计算。
4. 达到目标那么屏尺寸变化时1rem(基础块)也会变化,自然就是等比缩放。
##### 方案二rem+ flexible.js+less
和上个方案实现原理一样都是通过改变1rem(基础块)大小实现页面整体元素改变;
**filexible.js**
* 手机淘宝团队出的 简洁高效 移动端适配库;<font color = red>和flex布局没有任何关系</font>
* github地址https://github.com/amfe/lib-flexible
* 不是通过设置CSS媒体查询设置font-size通过 JS 设置font-size效果是屏幕变化一点就有一个rem重新计算
```javascript
function setRem () {
// docEl.clientWidth JS获取当前屏幕的宽度
// 除以10,得到基础块,(将屏幕划分为10块)
var rem = docEl.clientWidth / 10;
docEl.style.fontSize = rem + 'px'
}
```
举个例子:
* 假如拿到屏幕宽度按430px设计的设计稿
* 拿到UI设计稿原稿实现页面上所有的元素在设计稿上进行测量代码实现流式、flex只要是UI给图上有标注就是写出来先全部实现出来一会儿统一替换
* 在哪里写less文件
* 需要把生成的css文件进行引入index.html
* 设计稿宽度/10 1rem = 43px
* 统一替换100px=100/43 rem;
> **两种方案的对比**
>
> * 相同:
> * 都是对font-size实现控制1rem基础块变化实现等比效果
> * 不同:
> * rem+媒体查询+less通过设置不同的档位下设置不同的1rem值效果为阶梯式变化
> * flexible.js+rem通过js设置不同的1rem值效果为连续变化这个看起来更为连贯适配任何屏幕。
### 响应式布局
#### 介绍
响应式布局可以通过同一份代码快速、有效适配手机、平板、PC设备等所有的屏幕。
响应式布局涉及屏幕宽度变化(媒体查询)和布局知识[传统布局方案(百分比、浮动、清除浮动、定位)]
#### 档位划分
媒体查询:档位划分;市场上默认的划分,三个节点、四个档位
* w<768 超小屏幕xs手机
* 768<= w <992 小屏设备sm平板
* 992<= w <1200 中等屏幕md小显示屏的PC显示器
* 1200<=w 大宽屏设备lg大桌面显示器
![](https://i.loli.net/2020/11/05/tS6KdNzboRBkLiw.png)
```css
/*把市场上所有屏幕包括在内:*/
/* 1. 超小屏幕下 xs 小于 768 */
@media screen and (min-width: 0px) {
}
/* 2. 小屏幕下 sm 大于等于768 */
@media screen and (min-width: 768px) {
}
/* 3. 中等屏幕下 md 大于等于 992px */
@media screen and (min-width: 992px) {
}
/* 4. 大屏幕下 lg 大于等于1200 */
@media screen and (min-width: 1200px) {
}
```
#### 版心
不同的档位下,版心不同;所有的子元素都是归于版心下,不同的版心宽度,意味着子元素要以不同的布局排版满足用户浏览友好的需求;
```css
/* 1. 超小屏幕下 xs 小于 768 布局容器的宽度为 100% */
@media screen and (max-width: 767px) {
.container {
width: 100%;
}
}
/* 2. 小屏幕下 sm 大于等于768 布局容器改为 750px */
@media screen and (min-width: 768px) {
.container {
width: 750px;
}
}
/* 3. 中等屏幕下 md 大于等于 992px 布局容器修改为 970px */
@media screen and (min-width: 992px) {
.container {
width: 970px;
}
}
/* 4. 大屏幕下 lg 大于等于1200 布局容器修改为 1170 */
@media screen and (min-width: 1200px) {
.container {
width: 1170px;
}
}
```
> 注意:
>
> * 媒体查询使用符号的相关min-max-包含等号后面是数值单位为px
> * 除超小屏以外:版心的宽度设置都是小于当前档位最小界值,比如 min-width: 768px版心是750px两边留空白用户体验好。
> * 以上是市场默认划分,可根据自己需求添加档位;
#### [BootStrap](https://www.bootcss.com/)
BootStrap框架可快速搭建出响应式页面
* BootStrap 出自 Twitter推特是目前最受欢迎的前端响应式框架。
* 网址:
* 中文网http://www.bootcss.com/
* 版本:
* 2.x.x停止维护代码不够简洁功能不够完善。
* 3.x.x目前使用最多稳定不支持IE6-IE7。对 IE8 支持界面效果不好偏向用于开发响应式布局、移动设备优先的WEB 项目。
* 4.x.x最新版目前还不是很流行
**使用**
使用前需要先去官网下载https://v3.bootcss.com/getting-started/,如无特殊需求,建议下载用于生产环境的。
![](https://i.loli.net/2020/11/05/I8aFMTEqcypOxXZ.png)
下载完成后,将其整个文件夹放入你的项目中。
初始化html文件
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<!-- 要求 当前网页 使用 IE浏览器 最高版本的内核 来渲染 -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- 视口的设置视口的宽度和设备一致默认的缩放比例和PC端一致用户不能自行缩放 -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>BootStrap Template</title>
<!-- Bootstrap 的文件引入-->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--解决ie9以下浏览器对html5新增标签的不识别并导致CSS不起作用的问题-->
<!--解决ie9以下浏览器对 css3 Media Query 的不识别 -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!-- 条件注释:解决小于IE9的版本一些问题 -->
<!--[if lt IE 9]>
<script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<h1>你好,世界!</h1>
</body>
</html>
```
> 条件注释:满足条件,下面代码链接就会发出请求;
>
> ```css
> [if lt IE 9]
> <script src="//cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
> <script src="//cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
> [endif]
> ```
##### 布局容器
* 版心设置BootStrap 需要为页面内容包裹一个 .container 或者.container-fluid 容器,它提供了两个作此用处的类。
* `.container`:设置不同档位下的版心的宽度;
* 超小屏xs : extra small手机 0px <=w 版心宽度为100%
* 小屏sm : small :平板; 768px<=w ;版心宽度定为 750px
* 中屏md: medium桌面992px<=w ;版心宽度定为 970px
* 大屏lg: large大桌面1200px<=w ;版心宽度定为 1170px
* .container-fluid百分百宽度
* 特点:
* 所有元素为CSS3盒子模型
* 布局盒子有左右15px padding值
##### Bootstrap预制类名
* 排版
```html
<h1>h1. Bootstrap heading</h1>
<h2>h2. Bootstrap heading</h2>
...
<h6>h6. Bootstrap heading</h6>
<p>...</p>
```
更多内容可以参考https://v3.bootcss.com/css/#type
* 按钮
```html
<a class="btn btn-default" href="#" role="button">Link</a>
<button class="btn btn-default" type="submit">Button</button>
<input class="btn btn-default" type="button" value="Input">
<input class="btn btn-default" type="submit" value="Submit">
```
更多内容可以参考https://v3.bootcss.com/css/#buttons
* 辅助类样式
```html
<!-- 上下文颜色 -->
<p class="text-muted">...</p>
<!-- 下拉三角 -->
<span class="caret"></span>
```
更多内容可以参考https://v3.bootcss.com/css/#helper-classes
* 字体图标
```html
<!-- 搜索🔍 -->
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
```
更多内容可以参考https://v3.bootcss.com/components/#glyphicons
##### Bootstrap栅格系统
栅格系统可以设置子元素在不同档位下的布局;
栅格系统在各个档位下控制子元素布局不同将版心宽度均分为12份
各个档位下都有预制好的类前缀:
![](https://i.loli.net/2020/11/05/v5pARWne17VXTZ9.png)
栅格系统用于通过一系列的**行row与列column的组合**来创建页面布局,你的内容就可以放入这些创建好的布局中,控制不同的档位下,**列的子元素占有几份**
**基本使用:**
```html
<!-- 中屏和以上占有6份 -->
<div class="container">
<div class="row">
<div class="col-md-6">.col-md-6</div>
<div class="col-md-6">.col-md-6</div>
</div>
</div>
<!-- 各个档位下,按照各个档位下布局 -->
<div class="container">
<div class="row">
<div class="col-md-6 col-lg-4">1</div>
<div class="col-md-6 col-lg-8">2</div>
</div>
</div>
```
* 单一类前缀:各个档位下的类前缀,为包括当前且向上生效;例如:.col-md-6为中屏和以上占有6份
* 多个类前缀:分别按照各个档位列划分生效;
* 每个子项默认左右15px的padding
* 行(.row 可以去除父容器左右15px的padding值.row的左右margin为-15px
**列嵌套**
可以在已经分好的子元素中内部继续进行列的划分共12份继续在分好的布局内继续划分
```html
<!-- 直接嵌套 -->
<div class="col-sm-4">
<div class="col-sm-6">小列</div>
<div class="col-sm-6">小列</div>
</div>
<!-- 使用row嵌套 -->
<div class="col-sm-4">
<!-- 加1个行 row 这样可以表现出抵消父元素的左右15padding值 而且高度自动和父级一样高; -->
<div class="row">
<div class="col-sm-6">小列</div>
<div class="col-sm-6">小列</div>
</div>
</div>
```
**列偏移:**
划分好的子项进行列的份数偏移,场景:左右布局,居中布局;
```html
<!-- 左右对齐-->
<div class="row">
<!-- 如果只有一个盒子 那么就偏移 = 12-4-4 -->
<div class="col-lg-4">1</div>
<div class="col-lg-4 col-lg-offset-4">2</div>
</div>
<!-- 居中-->
<div class="row">
<!-- 如果只有一个盒子 那么就偏移 = 2 8 2 -->
<div class="col-md-8 col-md-offset-2">中间盒子</div>
</div>
```
栅格系统相关内容可以参考https://v3.bootcss.com/css/#grid
##### 响应式工具
![](https://i.loli.net/2020/11/05/HPAdJC73MOzXIbo.png)
* 注意:和列类前缀的参数形成对比记忆,
* col-sm-* 是超小屏(包含)以上的屏幕都是这个份数的划分;
* 响应式工具 只是对当前档位下的类前缀类名生效;
响应式工具相关内容可以参考https://v3.bootcss.com/css/#responsive-utilities

View File

@ -0,0 +1,84 @@
---
title: 简单的Java加减乘除计算器(适合新手)
date: 2020-05-30 22:59:13
tags:
- Java
- 代码
categories:
- Java练习
---
本人Java新手一枚刚学完Java数据类型、流程控制、数组、方法等基础语法知识。
尝试写了一个简单的计算器,实现了加减乘除功能,并可以循环接收数据。
代码有待改进,希望各位大佬多多指点 :beers:
<!-- more -->
```java
public class calculator {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(true){
System.out.println("请输入需要计算的第一个数字");
double a = in.nextDouble();
System.out.println("请输入需要计算的第二个数字");
double b = in.nextDouble();
while(true) {
System.out.println("请输入运算方式(+ - * /)");
String operation = in.next();
switch (operation) {
case "+":
System.out.println(add(a,b));
break;
case "-":
System.out.println(subtraction(a, b));
break;
case "*":
System.out.println(multiply(a, b));
break;
case "/":
System.out.println(division(a, b));
break;
default:
System.out.println("输入不正确,请重新输入");
}
break;
}
while (true) {
System.out.println("是否继续使用? " + "YES/NO");
String choose = in.next();
if (choose.equals("YES")) {
break;
} else if (choose.equals("NO")) {
System.out.println("欢迎下次使用,再见");
return;
} else {
System.out.println("输入不正确,请重新输入");
}
}
}
}
//加
private static double add(double a,double b){
return a+b;
}
//减
private static double subtraction(double a,double b){
return a-b;
}
//乘
private static double multiply(double a,double b){
return a*b;
}
//除
private static double division(double a,double b){
if(b==0){
System.out.println("被除数不能为0");
return 0 ;
}
return a/b;
}
}
```

View File

@ -0,0 +1,361 @@
---
title: 计算机硬件核心基础
date: 2020-05-07 10:43:18
tags:
- 计算机组成
- 计算机硬件
- 操作系统
categories:
- 计算机基础
---
## 前言
先来了解一些基本概念:
**`编程语言`**本质是一门语言,语言就是一种事物与另外一种事物沟通的表达方式/工具,那么编程语言就是**人**与**计算机**之间沟通的方式。
<!--more-->
**`编程`**就是人类把自己想让计算机做的事,也就是自己的思维逻辑,用编程语言表达出来。
**`编程的目的`**就是让计算机按照人类的思维逻辑去工作,从而解放人力。
![1](https://i.loli.net/2020/05/07/hg3NOqwCmSMkfGj.jpg)
## 计算机组成原理
> ![简单计算机组件](https://i.loli.net/2020/05/16/Hr8qJpKlM3tcuIi.jpg)
### 计算机五大组成部分
#### **`控制器`**
**控制器**是计算机的指挥系统。控制器通过地址访问存储器,从存储器中取出指令,经译码器分析后,根据指令分析结果产生相应的操作控制信号作用于其他部件,使得各部件在控制器控制下有条不紊地协调工作。
#### **`运算器`**
**运算器**是实现算术运算和逻辑运算的部件。
**`控制器 + 运算器 = CPU`**
#### **`存储器`**
**存储器**是计算机用来存放所有数据和程序的记忆部件。它的基本功能是按指定的地址存(写)入或者取(读)出信息。
计算机中的存储器可分成两大类:一类是内存储器,简称**内存或主存**;另一类是外存储器(辅助存储器),简称**外存或辅存**。 存储器由若干个存储单元组成,每个存储单元都有一个地址,计算机通过地址对存储单元进行读写。一个存储器所包含的字节数称为**存储容量**单位有B、KB、MB、GB、TB等。
* **内存:** 存取数据快;断电数据丢失,只能临时存取数据。
* **外存:**存取数据慢;断电数据不会丢失,用来永久保存数据 。
内存的存取速度要远高于外存。
#### **`输入设备input`**
**输入设备**是计算接收外界输入数据的工具,如键盘、鼠标。
#### **`输出设备output`**
**输出设备**是计算机向外输出数据的工具,如显示器、打印机。
存储器如内存、磁盘等既是输入设备又是输出设备统称为IO设备
> ![img](https://i.loli.net/2020/05/16/4aDRbLGvfy7wrAs.png)
CPU存取的数据和指令都来自主存储器(内存) 。
内存称之为主存主存储器内的数据则是从输入单元所传输进来而CPU处理完毕的数据也必须先写回主存储器中最后数据才从主存储器传输到输出单元。
### 程序运行与三大核心硬件(CPU 内存 硬盘)的关系
我们编写的程序一定是要运行于计算机硬件之上而站在硬件的角度与运行程序有关的三大核心硬件为CPU、内存、硬盘。
程序最先是存放于硬盘中的程序的运行是先从硬盘把代码加载到内存中然后CPU是从内存中读取指令运行。
## 操作系统
### 操作系统的由来
大前提:我们编程目的就是为了奴役计算机,让计算机硬件自发地运行起来,然而硬件毕竟是”死的“,**硬件的运行都是由软件支配**。
倘若我们要开发一个应用程序,在没有操作系统之前,开发者在编写业务逻辑之前,必须先编写一套完整的控制程序来控制所有的硬件基本运行(这要求开发者需要详细了解计算机硬件的各种控制细节例如要熟悉CPU里面所有的指令集),如此,所有开发者在开发程序时都必须按以下两个步骤:
```tex
1.编写一套完整的的控制程序,用来控制硬件的基本运行,以及把复杂的硬件的操作封装成简单的接口
2.基于控制程序的接口开发包含一系列业务逻辑的程序,为了与控制程序区分,可以称为应用程序.
```
综上,对于不同的应用程序来说,应用程序的业务逻辑各不相同,但硬件的控制程序都大致相同,为了避免所有开发者做重复劳动,以及不用再耗费精力去了解所有硬件的运行细节,有公司专门跳出来承担起控制程序的开发任务,这里所说的控制程序指的就是操作系统。
**`操作系统`**是一个协调、管理、控制计算机硬件资源与应用软件资源的控制程序。它位于计算机硬件与应用软件之间,起承上启下的作用。
**操作系统的功能:**
* 控制计算机硬件的基本运行
* 帮我们把复杂的硬件的控制封装成简单的接口,对于开发应用程序来说只需要调用操作系统提供给我们的接口即可
### 系统软件与应用软件
* 系统软件:
指控制和协调计算机及外部设备、支持应用软件开发和运行的系统,是无需用户干预的各种程序的集合,主要功能是调度、监控和维护计算机系统;负责管理计算机系统中各种独立的硬件,使得它们可以协调工作。系统软件使得计算机使用者和其他软件将计算机当作一个整体而不需要顾及到底层每个硬件是如何工作的。
一般来讲,系统软件包括操作系统和一系列基本的工具(比如编译器,数据库管理,存储器格式化,文件系统管理,用户身份验证,驱动管理,网络连接等方面的工具),是支持计算机系统正常运行并实现用户操作的那部分软件。
* 应用软件:
应用软件(Application是和系统软件相对应的是用户可以使用的各种程序设计语言以及用各种程序设计语言编制的应用程序的集合分为应用软件包和用户程序。应用软件包是利用计算机解决某类问题而设计的程序的集合多供用户使用。
应用软件是为满足用户不同领域、不同问题的应用需求而提供的那部分软件。 它可以拓宽计算机系统的应用领域,放大硬件的功能。
### 计算机系统三层结构
我们开发应用程序本质是在控制硬件,但是我们直接打交道的是操作系统,应用程序都是通过操作系统来间接地操作硬件的,所以一套完整的计算机系统分为三层,如下:
> ![计算机系统三层结构](https://i.loli.net/2020/04/20/nrdy8V6NIoPLhiD.jpg)
### 平台与跨平台的概念
应用程序都是运行于操作系统之上,而操作系统则是运行于硬件之上的,所以承载应用程序的是一台运行有操作系统的计算机,称之为应用程序的运行平台,即:**`硬件 + 操作系统 = 平台`**。
> ![平台](https://i.loli.net/2020/04/20/iBWhvPRqGZ14ry5.jpg)
常见的平台有windows系统+某款硬件、linux系统+某款硬件、ubuntu+某款硬件等,我们在开发应用程序时就需要考虑到应用程序的**跨平台**性,如果能开发出一款可以在任意平台运行的应用程序,那对于开发者来说真是极大的福音。
跨平台即不依赖于操作系统,也不依赖硬件环境。一个操作系统下开发的应用,放到另一个操作系统下依然可以运行。而决定应用软件的跨平台性的关键因素往往是编程语言的选择,一般解释型语言(即不需编译的语言比如PHP、Python等)都可跨平台运行;有些编译型语言(如Java等)由于其本身的特性(不同平台有不同的库、具有跨平台的扩展以及中间件),也可跨平台运行。
## 知识拓展
### CPU详解
#### CPU的分类与指令集
CPU内部是含有微指令集的我们所使用的的软件都要经过CPU内部的微指令集来完成才行。这些指令集的设计主要又被分为两种设计理念这就是目前世界上常见到的两种主要的CPU种类分别是精简指令集RISC与复杂指令集CISC系统。下面我们就来谈谈这两种不同CPU种类的差异
1.**`精简指令集`**
精简指令集(Reduced Instruction Set ComputingRISC)这种CPU的设计中微指令集较为精简每个指令的运行时间都很短完成的动作也很单纯指令的执行效能较佳但是若要做复杂的事情就要由多个指令来完成。常见的RISC指令集CPU主要例如Sun公司的SPARC系列、IBM公司的Power Architecture包括PowerPC系列、与ARM系列等。【注Sun已经被Oracle收购】
SPARC架构的计算机常用于学术领域的大型工作站中包括银行金融体系的主服务器也都有这类的计算机架构
PowerPC架构的应用如Sony出产的Play Station 3PS3使用的就是该架构的Cell处理器。
ARM是世界上使用范围最广的CPU常用的各厂商的手机、PDA、导航系统、网络设备等几乎都用该架构的CPU。
2.**`复杂指令集`**
复杂指令集Complex Instruction Set ComputerCISC与RISC不同在CISC的微指令集中每个小指令可以执行一些较低阶的硬件操作指令数目多而且复杂每条指令的长度并不相同。因此指令执行较为复杂所以每条指令花费的时间较长但每条个别指令可以处理的工作较为丰富。常见的CISC微指令集CPU主要有AMD、Intel、VIA等的x86架构的CPU。
总结:
CPU按照指令集可以分为精简指令集CPU和复杂指令集CPU两种区别在于前者的指令集精简每个指令的运行时间都很短完成的动作也很单纯指令的执行效能较佳但是若要做复杂的事情就要由多个指令来完成。后者的指令集每个小指令可以执行一些较低阶的硬件操作指令数目多而且复杂每条指令的长度并不相同。因为指令执行较为复杂所以每条指令花费的时间较长但每条个别指令可以处理的工作较为丰富。
#### x86-64
**``x86架构``**
x86是针对cpu的型号或者说架构的一种统称详细地讲最早的那颗Intel发明出来的CPU代号称为8086后来在8086的基础上又开发出了80285、80386....因此这种架构的CPU就被统称为x86架构了。
由于AMD、Intel、VIA所开发出来的x86架构CPU被大量使用于个人计算机上面因此个人计算机常被称为x86架构的计算机
程序员开发出的软件最终都要翻译成cpu的指令集才能运行因此软件的版本必须与cpu的架构契合举个例子我们在MySQL官网下载软件MySQL时名字为``Windows(x86,32-bit),ZIP Archive (mysql-5.7.20-win32.zip)``我们发现名字中有x86这其实就是告诉我们该软件应该运行在x86架构的计算机上。
**``64位 ``**
cpu的位数指的是cpu一次性能从内存中取出多少位二进制指令64bit指的是一次性能从内存中取出64位二进制指令。
在2003年以前由Intel所开发的x86架构CPU由8位升级到16、32位后来AMD依此架构修改新一代的CPU为64位到现在个人计算机CPU通常都是x86_64的架构。
cpu具有向下兼容性指的是64位的cpu既可以运行64位的软件也可以运行32位的软件而32位的cpu只能运行32位的软件。这其实很好理解如果把cpu的位数当成是车道的宽而内存中软件的指令当做是待通行的车辆宽64的车道每次肯定既可以通行64辆车也可以通信32辆车而宽32的车道每次却只能通行32辆车
#### 运算器与控制器
常将运算器和控制器合称为中央处理器(Central Processing UnitCPU)。其中运算器用来主要负责程序运算与逻辑判断控制器则主要协调各组件和各单元的工作所以CPU的工作主要在于管理和运算。可以说计算机的大脑就是CPU。
**`1.运算器`**
运算器是对信息进行处理和运算的部件。经常进行的运算是算术运算和逻辑运算所以运算器又可称为算术逻辑运算部件Arithmetic and LogicalALU
运算器的核心是加法器。运算器中还有若干个通用寄存器或累加寄存器,用来暂存操作数并存放运算结果。寄存器的存取速度比存储器的存放速度快很多。
**`2.控制器`**
控制器是整个计算机的指挥中心,它的主要功能是按照人们预先确定的操作步骤,控制整个计算机的各部件有条不紊的自动工作。
控制器从主存中逐条地读取出指令进行分析,根据指令的不同来安排操作顺序,向各部件发出相应的操作信号,控制它们执行指令所规定的任务。控制器中包括一些专用的寄存器。
#### 寄存器
寄存器是中央处理器内的组成部份。它跟CPU有关。寄存器是有限存贮容量的高速存贮部件它们可用来暂存指令、数据和位址。在中央处理器的控制部件中包含的寄存器有指令寄存器(IR)和程序计数器(PC)。在中央处理器的算术及逻辑部件中,包含的寄存器有累加器(ACC)。
> ![img](https://i.loli.net/2020/05/16/l1qb8EsJoZPtx4m.jpg)
#### 内核态与用户态
除了在嵌入式系统中的非常简单的CPU(如:单片机)之外多数CPU都有两种模式即**`内核态与用户态`**。
通常,计算机由[PSW](https://baike.baidu.com/item/PSW/1878339?fr=aladdin)(程序状态寄存器)控制这两种模式。
**`内核态:`**当cpu在内核态运行时cpu可以执行指令集中所有的指令很明显所有的指令中包含了使用硬件的所有功能操作系统在内核态下运行从而可以访问整个硬件
**`用户态:`**用户程序在用户态下运行仅仅只能执行cpu整个指令集的一个子集该子集中不包含操作硬件功能的部分因此一般情况下在用户态中有关I/O和内存保护操作系统占用的内存是受保护的不能被别的程序占用当然在用户态下将PSW中的模式设置成内核态也是禁止的。
**`内核态与用户态切换:`**
用户态下工作的软件不能操作硬件,但是我们的软件一定会有操作硬件的需求,比如从磁盘上读一个文件,那就必须经历从用户态切换到内核态的过程,为此,用户程序必须使用[系统调用(system call)](https://baike.baidu.com/item/系统调用/861110),通过相应的指令把用户态切换成内核态。
把系统调用看成一个特别的过程调用指令就可以了,该指令具有从用户态切换到内核态的特别能力。
#### 多线程与多核芯片
在一个CPU中增加多个处理逻辑称为多线程或超线程该概念是由Inter公司首次提出。
多核就是多个完整的CPU处理器。
比如我们常说的四核八线程就是指有四个CPU,每个CPU中有两个线程。
> <img src="https://i.loli.net/2020/05/03/L4eNdiVUZ3AYOgs.png" alt="1" style="zoom: 80%;" />
>
> <img src="https://i.loli.net/2020/05/03/Ix8Ogqi9DKUa36H.png" alt="2" style="zoom:80%;" />
### 存储器相关
> ![存储层次结构](https://i.loli.net/2020/05/16/Ko49glFa7BZUNXV.jpg)
存储器系统采用如上图的分层结构,顶层的存储器速度较高,容量较小,与底层的存储器相比每位的成本较高,其差别往往是十亿数量级的。
#### 寄存器即L1缓存
用与cpu相同材质制造与cpu一样快因而cpu访问它无时延典型容量是在32位cpu中为32\*32在64位cpu中为64\*64在两种情况下容量均小于1KB。
#### 高速缓存即L2缓存
主要由硬件控制高速缓存的存取内存中有高速缓存行按照0\~64字节为行064~127为行1…
最常用的高速缓存行放置在cpu内部或者非常接近cpu的高速缓存中。当某个程序需要读一个存储字时高速缓存硬件检查所需要的高速缓存行是否在高速缓存中。如果是则称为**高速缓存命中**,缓存满足了请求,就不需要通过总线把访问请求送往主存(内存),这毕竟是慢的。高速缓存的命中通常需要两个时钟周期。**高速缓存未命中**,就必须访问内存,这需要付出大量的时间代价。由于高速缓存价格昂贵,所以其大小有限,有些机器具有两级甚至三级高速缓存,每一级高速缓存比前一级慢但是容量大。
缓存在计算机科学的许多领域中起着重要的作用并不仅仅只是RAM随机存取存储器的缓存行。只要存在大量的资源可以划分为小的部分那么这些资源中的某些部分肯定会比其他部分更频发地得到使用此时用缓存可以带来性能上的提升。一个典型的例子就是操作系统一直在使用缓存比如多数操作系统在内存中保留频繁使用的文件的一部分以避免从磁盘中重复地调用这些文件类似的/root/a/b/c/d/e/f/a.txt的长路径名转换成该文件所在的磁盘地址的结果然后放入缓存可以避免重复寻找地址还有一个web页面的url地址转换为网络地址(IP)地址后,这个转换结果也可以缓存起来供将来使用。
缓存是一个好方法在现代cpu中设计了两个缓存再看3.1.5中的两种cpu设计图。第一级缓存称为L1总是在CPU中通常用来将已经解码的指令调入cpu的执行引擎对那些频繁使用的数据字多数芯片还会安装第二L1缓存 … 另外往往设计有二级缓存L2用来存放近来经常使用的内存字。L1与L2的差别在于对cpu对L1的访问无时间延迟而对L2的访问则有1-2个时钟周期即1-2ns的延迟。
#### 内存
再往下一层是主存,此乃存储器系统的主力,主存通常称为**随机访问存储(可读可写)`RAM`**,就是我们通常所说的内存,容量一直在不断攀升,所有不能再高速缓存中找到的,都会到主存中找,**主存是易失性存储,断电后数据全部消失**。
除了主存RAM之外许多计算机已经在使用少量的**非易失性随机访问存储如`ROM`(Read Only Memory)**在电源切断之后非易失性存储的内容并不会丢失ROM只读存储器在工厂中就被编程完毕然后再也不能修改。ROM速度快且便宜在有些计算机中用于启动计算机的引导加载模块(BIOS)就存放在ROM中另外一些I/O卡也采用ROM处理底层设备的控制。
**`EEPROM`Electrically Erasable PROM电可擦除可编程ROM和`闪存`flash memory也是非易失性的**但是与ROM相反他们可以擦除和重写。不过重写时花费的时间比写入RAM要多。在便携式电子设备中中闪存通常作为存储媒介。闪存是数码相机中的胶卷是便携式音译播放器的磁盘还应用于固态硬盘。闪存在速度上介于RAM和磁盘之间但与磁盘不同的是闪存擦除的次数过多就被磨损了。
还有一类存储器就是**`CMOS`,它是易失性的**许多计算机利用CMOS存储器来**保持当前时间和日期**。CMOS存储器和递增时间的电路由一小块**电池驱动**,所以,即使计算机没有加电,时间也仍然可以正确地更新,除此之外**CMOS还可以保存配置的参数比如哪一个是启动磁盘等**之所以采用CMOS是因为它耗电非常少一块工厂原装电池往往能使用若干年但是当电池失效时相关的配置和时间等都将丢失
#### 硬盘(磁盘/机械硬盘)
> ![3](https://i.loli.net/2020/05/03/17kJ8TzIfXl4rix.png)
>
> <img src="https://i.loli.net/2020/05/03/cNI7GgKnPJVzvMS.png" alt="4" style="zoom:80%;" />
磁盘低速的原因是因为它一种机械装置在磁盘中有一个或多个金属盘片它们以54007200或10800rpmRPM =revolutions per minute 每分钟多少转 的速度旋转。从边缘开始有一个机械臂悬在盘面上这类似于老式黑胶唱片机上的拾音臂。信息卸载磁盘上的一些列的同心圆上是一连串的2进制位称为bit位为了统计方法8个bit称为一个字节Bytes1024Bytes=1kB1024kB=1MB1024MB=1GB1024GB=1TB1024TB = 1PB所以我们平时所说的磁盘容量最终指的就是磁盘能写多少个2进制位。
每个磁头可以读取一段换新区域,称为**`磁道`**。
把一个机械手臂位置上所有的磁道合起来,组成一个**`柱面`**。
每个磁道划成若干**`扇区`**站在硬盘的角度一次性读写数据的最小单位为扇区一个扇区通常为512Bytes。
操作系统一次性读写的单位是一个Block块默认是8个扇区也就是4096Bytes
#### 硬盘的IO延迟问题
**数据都存放于一段一段的扇区,即磁道这个圆圈的一小段圆圈,从磁盘读取一段数据需要经历寻道时间和延迟时间**
**平均寻道时间:**
机械手臂从一个柱面随机移动到相邻的柱面的时间称为寻道时间,找到了磁道就意味着找到了数据所在的那个圈圈,但是还不知道数据具体这个圆圈的具体位置。受限于物理工艺水平。
**平均延迟时间:**
机械臂到达正确的磁道之后还必须等待旋转到数据所在的扇区下,这段时间称为延迟时间。受限于硬盘的转速!
IO延迟 = 平均寻道时间+平均延期时间。
> **`优化程序运行效率的一个核心法则:能从内存取数据,就不要从硬盘取数据`**
#### 虚拟内存
许多计算机支持虚拟内存机制该机制使计算机可以运行大于物理内存的程序方法是将正在使用的程序放入内存执行而暂时不需要执行的程序放到磁盘的某块地方这块地方成为虚拟内存在linux中称为swap这种机制的核心在于快速地映射内存地址由cpu中的一个部件负责成为存储器管理单元(Memory Management Unit MMU)
> 从一个程序切换到另外一个程序,称为上下文切换(context switch),缓存和MMU的出现提升了系统的性能尤其是上下文切换。
> PS磁带
>
> 在价钱相同的情况下比硬盘拥有更高的存储容量,虽然速度低于磁盘,但是因其大容量,在地震水灾火灾时可移动性强等特性,常被用来做备份。(常见于大型数据库系统中)
### IO设备
**IO设备 = 设备的控制器+设备本身**
cpu和存储器并不是操作系统唯一需要管理的资源I/O设备也是非常重要的一环。
见1.1的图,**I/O设备一般包括两个部分设备控制器和设备本身**。
控制器:是查找主板上的一块芯片或一组芯片(硬盘,网卡,声卡等都需要插到一个口上,这个口连的便是控制器),控制器负责控制连接的设备,它从操作系统接收命令,比如读硬盘数据,然后就对硬盘设备发起读请求来读出内容。
控制器的功能:通常情况下对设备的控制是非常复杂和具体的,控制器的任务就是为操作系统屏蔽这些复杂而具体的工作,提供给操作系统一个简单而清晰的接口
设备本身:有相对简单的接口且标准的,这样大家都可以为其编写驱动程序了。要想调用设备,必须根据该接口编写复杂而具体的程序,于是有了控制器提供设备驱动接口给操作系统。必须把设备驱动程序安装到操作系统中。
### 总线
在第1节的结构在小型计算机中沿用了多年并也用在早期的IBM PC中。但是随着处理器和存储器速度越来越快单总线很难处理总线的交通流量了于是出现了下图的多总线模式他们处理I/O设备及cpu到存储器的速度都更快。
北桥即PCI桥连接高速设备
南桥即ISA桥连接慢速设备
> ![](https://images2015.cnblogs.com/blog/1036857/201701/1036857-20170118183358656-1969770652.png)
主板图解:
![](https://images2018.cnblogs.com/blog/1036857/201803/1036857-20180314164300354-1096940375.jpg)
### 操作系统启动流程
在计算机的主板上有一个基本的输入输出程序Basic Input Output System)
BIOS就相当于一个小的操作系统它有底层的I/O软件包括读键盘写屏幕进行磁盘I/O,该程序存放于一非易失性存储ROM中。
**启动流程:**
1.计算机加电
2.BIOS开始运行检测硬件cpu、内存、硬盘等
3.BIOS读取CMOS存储器中的参数选择启动设备
4.从启动设备上读取第一个扇区的内容MBR主引导记录512字节前446为引导信息后64为分区信息最后两个为标志位
5.根据分区信息读入bootloader启动装载模块启动操作系统
6.然后操作系统询问BIOS以获得配置信息。对于每种设备系统会检查其设备驱动程序是否存在如果没有系统则会要求用户安装设备驱动程序。一旦有了全部的设备驱动程序操作系统就将它们调入内核。然后初始有关的表格如进程表传进需要的进程并在每个终端上启动登录程序或GUI
> 补充:**应用程序的启动流程**
>
> 1. 双击exe快捷方式该快捷方式指向一个绝对路径
> 2. 操作系统会根据路径找到exe程序在硬盘中的位置控制其代码从硬盘加载到内存
> 3. 然后CPU从内存中读取刚刚读入内存的程序代码执行应用程序完成启动
## 参考:
[1] https://www.cnblogs.com/linhaifeng/p/6523843.html#4462371
[2] https://zhuanlan.zhihu.com/p/108350791

View File

@ -0,0 +1,145 @@
---
title: 过滤器(Filter)和监听器(Listener)
date: 2020-12-12 13:54:10
tags:
- JavaWeb
- filter
- listener
categories:
- JavaWeb
---
## 过滤器(Filter)
### 过滤器定义
过滤器实际上就是对web资源进行拦截做一些处理后再交给下一个过滤器或servlet处理通常都是用来拦截request进行处理的也可以对返回的response进行拦截处理.
![](https://i.loli.net/2020/11/26/IPunhxFN9Vsjbqo.png)
过滤器的特点在servlet之前和之后都会被执行
<!--more-->
### Filter使用
1. 创建一个类**实现Fiter接口**javax.servlet.Filter例如以下代码是简单的字符编码过滤器
```java
@WebFilter(filterName = "encodingFilter",urlPatterns = "/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//初始化过滤器
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
//具体的执行逻辑
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset = utf-8");
//执行完过滤跳转到原请求目的地
chain.doFilter(req,resp);
}
@Override
public void destroy() {
//关闭过滤器
}
}
```
2. **部署Filter过滤器**
**方式一在web.xml文件中部署**
```xml
<filter>
<filter-name>过滤器名称</filter-name>
<filter-class>过滤器所在的路径</filter-class>
</filter>
<filter-mapping>
<filter-name>过滤器名称</filter-name>
<url-pattern>需要过滤的资源或请求</url-pattern>
</filter-mapping>
```
**方式二:通过@WebFilter注解部署**
如上面字符编码过滤器代码所示。
@WebFilter常用属性如下
| 属性名 | 类型 | 描述 |
| ------------ | -------- | ------------------------------------------------------------ |
| filterName | String | 指定过滤器的 name 属性,等价于 |
| value | String[] | 该属性等价于 urlPatterns 属性。但是两者不应该同时使用。 |
| urlPatterns | String[] | 指定一组过滤器的 URL 匹配模式。等价于标签。 |
| servletNames | String[] | 指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中 的取值。 |
### Fiter使用场景
```tex
1.防止用户未登录就执行后续操作
String name=(String)session.getAttribute("key");
if(name==null){
//跳转到登录页面
}
2.设置编码方式--统一设置编码
3.加密解密(密码的加密和解密)
4.非法文字筛选
5.下载资源的限制
......
```
##监听器(Listener)
### 监听器定义及分类
监听器就是监听某个域对象的的状态变化的组件。
> 监听器的相关概念:
>
> * 事件源:被监听的对象(三个域对象request、session、servletContext)
> * 监听器:监听事件源对象事件源对象的状态的变化都会触发监听器
> * 注册监听器:将监听器与事件源进行绑定
> * 响应行为:监听器监听到事件源的状态变化时所涉及的功能代码(程序员编写代码)
**分类:**
第一维度按照被监听的对象划分ServletRequest域、HttpSession域、ServletContext域
第二维度按照监听的内容分:监听域对象的创建与销毁的、监听域对象的属性变化的
![](https://i.loli.net/2020/11/26/3Wpr5yiDcYEf2IN.png)
### 监听器使用
根据不同的监听域实现不同的接口来创建Listener监听器。比如我们创建一个类来监听Session对象的创建与销毁
```java
@webListenet
public class MySessionListener implements HttpSessionListener{
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("session创建");
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("session销毁");
}
}
```
**监听器部署**
在web.xml文件中添加以下代码
```xml
<listener>
<listener-class>监听器所在的路径</listener-class>
</listener>
```
或者使用@WebListener注解

View File

@ -0,0 +1,5 @@
---
title: Categories
date: 2020-04-30 15:29:14
type: categories
---

BIN
source/img/alipay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

BIN
source/img/avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

BIN
source/img/favicon16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

BIN
source/img/favicon32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
source/img/index_img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 KiB

BIN
source/img/wechatpay.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

5
source/tags/index.md Normal file
View File

@ -0,0 +1,5 @@
---
title: Tags
date: 2020-04-30 15:32:18
type: tags
---

0
themes/.gitkeep Normal file
View File

View File

@ -0,0 +1,63 @@
name: Bug report
description: Create a report to help us improve
title: '[Bug]: '
body:
- type: markdown
attributes:
value: |
重要:請依照該模板來提交
Please follow the template to create a new issue
- type: input
id: butterfly-ver
attributes:
label: 使用的 Butterfly 版本? | What version of Butterfly are you use?
description: 檢視主題的 package.json | Check the theme's package.json
validations:
required: true
- type: dropdown
id: browser
attributes:
label: 使用的瀏覽器? || What browse are you using?
options:
- Chrome
- Edge
- Safari
- Opera
- Other
validations:
required: true
- type: dropdown
id: platform
attributes:
label: 使用的系統? || What operating system are you using?
options:
- Windows
- macOS
- Linux
- Android
- iOS
- Other
validations:
required: true
- type: textarea
id: description
attributes:
label: 問題描述 | Describe the bug
description: 請描述你的問題現象 | A clear and concise description of what the bug is.
placeholder: 請儘量提供截圖來定位問題 | If applicable, add screenshots to help explain your problem
value:
validations:
required: true
- type: input
id: website
attributes:
label: 出現問題網站 | Website
description: 請提供下可復現網站地址 | Please supply a website url which can reproduce problem.
placeholder:
validations:
required: true

View File

@ -0,0 +1,22 @@
blank_issues_enabled: false
contact_links:
- name: Questions about Butterfly
url: https://github.com/jerryc127/hexo-theme-butterfly/discussions
about: 一些使用問題請到 Discussion 詢問。 Please ask questions in Discussion.
- name: Butterfly Q&A
url: https://butterfly.js.org/posts/98d20436/
about: Butterfly Q&A
- name: Telegram
url: https://t.me/bu2fly
about: 'Official Telegram Group'
- name: QQ 1群
url: https://jq.qq.com/?_wv=1027&k=KU9105XR
about: '群號 1070540070不要兩個Q群都添加'
- name: QQ 2群
url: https://jq.qq.com/?_wv=1027&k=r1nK0DQz
about: '群號 978221020不要兩個Q群都添加'

View File

@ -0,0 +1,14 @@
name: Feature request
description: Suggest an idea for this project
title: '[Feature]: '
body:
- type: textarea
id: feature-request
attributes:
label: 想要的功能 | What feature do you want?
description: 請描述你需要的新功能 | A clear and concise description of what the feature is.
placeholder:
value:
validations:
require: true

20
themes/butterfly/.github/stale.yml vendored Normal file
View File

@ -0,0 +1,20 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
- security
- bug
- enhancement
- documentation
# Label to use when marking an issue as stale
staleLabel: stale
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

View File

@ -0,0 +1,19 @@
name: npm publish
on:
release:
types: [created]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v1
with:
node-version: '12.x'
registry-url: 'https://registry.npmjs.org'
- run: npm install
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

202
themes/butterfly/LICENSE Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

113
themes/butterfly/README.md Normal file
View File

@ -0,0 +1,113 @@
<div align="right">
Language:
🇺🇸
<a title="Chinese" href="/README_CN.md">🇨🇳</a>
</div>
# hexo-theme-butterfly
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master)
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/dev?label=dev)
![https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff](https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff)
![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c)
![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
Demo: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/)
Docs: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/)
Based on [hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody) theme.
## 💻 Installation
### GIT
> If you are in Mainland China, you can download in [Gitee](https://gitee.com/immyw/hexo-theme-butterfly.git)
Stable branch [recommend]:
```
git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly
```
Dev branch:
```
git clone -b dev https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly
```
### NPM
> It supports Hexo 5.0.0 or later
In Hexo site root directory
```powershell
npm i hexo-theme-butterfly
```
## ⚙ Configuration
Set theme in the hexo work folder's root config file `_config.yml`:
> theme: butterfly
If you don't have pug & stylus renderer, try this:
> npm install hexo-renderer-pug hexo-renderer-stylus
## 🎉 Features
- [x] Card UI Design
- [X] Support sub-menu
- [x] Two Column designs
- [x] Responsive Web Design
- [x] Dark Mode
- [x] Pjax
- [x] Read Mode
- [x] Conversion between Traditional and Simplified Chinese
- [X] TOC catalog is available for both computers and mobile phones
- [X] Color themes (darker/pale night/light/ocean/mac/mac light), support custom colors
- [X] Code Blocks (Display code language/close or expand Code Blocks/Copy Button/word wrap)
- [X] Disable copy/Add a Copyright Notice to the Copied Text
- [X] Search (Algolia SearchZ/Local Search)
- [x] Mathjax and Katex
- [x] Built-in 404 page
- [x] WordCount
- [x] Related articles
- [x] Displays outdated notice for a post
- [x] Share (AddThis/Sharejs/Addtoany)
- [X] Comment (Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42)
- [x] Multiple Comment System Support
- [x] Online Chats (Chatra/Tidio/Daovoice/Gitter/Crisp)
- [x] Web analytics
- [x] Google AdSense
- [x] Webmaster Verification
- [x] Change website colour scheme
- [x] Typewriter Effect: activate_power_mode
- [x] Background effects (Canvas ribbon/canvas_ribbon_piao/canvas_nest)
- [x] Mouse click effects (Fireworks/Heart/Text)
- [x] Preloader/Loading Animation
- [x] Busuanzi visitor counter
- [x] Medium Zoom/Fancybox
- [x] Mermaid
- [x] Justified Gallery
- [x] Lazyload images
- [x] Instantpage/Pangu/Snackbar notification toast/PWA......
## ✨ Contributors
<a href="https://github.com/jerryc127/hexo-theme-butterfly/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jerryc127/hexo-theme-butterfly" />
</a>
## 📷 Screenshots
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-1.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-2.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-3.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-4.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-1.png)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-2.png)

View File

@ -0,0 +1,113 @@
<div align="right">
語言:
中文
<a title="English" href="/README.md">英文</a>
</div>
# hexo-theme-butterfly
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/master?color=%231ab1ad&label=master)
![master version](https://img.shields.io/github/package-json/v/jerryc127/hexo-theme-butterfly/dev?label=dev)
![https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff](https://img.shields.io/npm/v/hexo-theme-butterfly?color=%09%23bf00ff)
![hexo version](https://img.shields.io/badge/hexo-5.3.0+-0e83c)
![license](https://img.shields.io/github/license/jerryc127/hexo-theme-butterfly?color=FF5531)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/theme-butterfly-readme.png)
預覽: 👍 [Butterfly](https://butterfly.js.org/) || 🤞 [CrazyWong](https://crazywong.com/)
文檔: 📖 [Butterfly Docs](https://butterfly.js.org/posts/21cfbf15/)
一款基於[hexo-theme-melody](https://github.com/Molunerfinn/hexo-theme-melody)修改的主題
## 💻 安裝
### Git 安裝
> 本倉庫同時上傳到 [Gitee](https://gitee.com/immyw/hexo-theme-butterfly.git),如果你訪問 Github 緩慢,可從 Gitee 中下載。
在博客根目錄裡安裝穩定版【推薦】
```powershell
git clone -b master https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly
```
如果想要安裝比較新的dev分支可以
```powershell
git clone -b dev https://github.com/jerryc127/hexo-theme-butterfly.git themes/butterfly
```
### npm 安裝
> 此方法只支持Hexo 5.0.0以上版本
在博客根目錄裡
```powershell
npm i hexo-theme-butterfly
```
## ⚙ 應用主題
修改hexo配置文件`_config.yml`,把主題改為`Butterfly`
```
theme: butterfly
```
>如果你沒有pug以及stylus的渲染器請下載安裝 npm install hexo-renderer-pug hexo-renderer-stylus --save
## 🎉 特色
- [x] 卡片化設計
- [X] 支持二級目錄
- [x] 雙欄設計
- [x] 響應式主題
- [x] 夜間模式
- [x] Pjax
- [x] 文章閲讀模式
- [x] 簡體和繁體轉換
- [X] 電腦和手機都可查看TOC目錄
- [X] 內置多種代碼配色darker/pale night/light/ocean/mac/mac light可自定義代碼配色
- [X] 代碼塊顯示代碼語言/關閉或展開代碼塊/代碼複製/代碼自動換行
- [X] 可關閉文字複製/可開啟內容複製增加版權信息)
- [X] 兩種搜索Algolia搜索和本地搜索
- [x] Mathjax 和 Katex
- [x] 內置404頁面
- [x] 顯示字數統計
- [x] 顯示相關文章
- [x] 過期文章提醒
- [x] 多種分享系統AddThis/Sharejs/Addtoany
- [X] 多種評論系統Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42
- [x] 支持雙評論部署
- [x] 多種在線聊天Chatra/Tidio/Daovoice/Gitter/Crisp
- [x] 多種分析系統
- [x] 谷歌廣告/手動廣告位置
- [x] 各種站長驗證Google/Bing/Baidu/360/Yandex
- [x] 修改網站配色
- [x] 打字特效 activate_power_mode
- [x] 多種背景特效(靜止彩帶/動態彩帶/Canvas Nest
- [x] 多種鼠標點擊特效(煙花/文字/愛心)
- [x] 內置一種 Preloader 加載動畫
- [x] 不蒜子訪問統計
- [x] 兩種大圖模式Medium Zoom/Fancybox
- [x] Mermaid 圖表顯示
- [x] 照片牆
- [x] 圖片懶加載
- [x] Instantpage/Pangu/Snackbar彈窗/PWA......
## ✨ 贡献者
<a href="https://github.com/jerryc127/hexo-theme-butterfly/graphs/contributors">
<img src="https://contrib.rocks/image?repo=jerryc127/hexo-theme-butterfly" />
</a>
## 📷 截圖
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-1.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-2.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-3.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN@m2/img/butterfly-readme-screenshots-4.jpg)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-1.png)
![](https://cdn.jsdelivr.net/gh/jerryc127/CDN/img/theme-butterfly-readme-homepage-2.png)

View File

@ -0,0 +1,914 @@
# Main menu navigation (導航目錄)
# see https://butterfly.js.org/posts/4aa8abbe/#導航菜單
# --------------------------------------
menu:
# Home: / || fas fa-home
# Archives: /archives/ || fas fa-archive
# Tags: /tags/ || fas fa-tags
# Categories: /categories/ || fas fa-folder-open
# List||fas fa-list:
# Music: /music/ || fas fa-music
# Movie: /movies/ || fas fa-video
# Link: /link/ || fas fa-link
# About: /about/ || fas fa-heart
# Code Blocks (代碼相關)
# --------------------------------------
highlight_theme: light # darker / pale night / light / ocean / mac / mac light / false
highlight_copy: true # copy button
highlight_lang: true # show the code language
highlight_shrink: false # true: shrink the code blocks / false: expand the code blocks | none: expand code blocks and hide the button
highlight_height_limit: false # unit: px
code_word_wrap: false
# copy settings
# copyright: Add the copyright information after copied content (複製的內容後面加上版權信息)
copy:
enable: true
copyright:
enable: false
limit_count: 50
# social settings (社交圖標設置)
# formal:
# icon: link || the description
social:
# fab fa-github: https://github.com/xxxxx || Github
# fas fa-envelope: mailto:xxxxxx@gmail.com || Email
# search (搜索)
# see https://butterfly.js.org/posts/ceeb73f/#搜索系統
# --------------------------------------
# Algolia search
algolia_search:
enable: false
hits:
per_page: 6
# Local search
local_search:
enable: false
preload: false
CDN:
# Math (數學)
# --------------------------------------
# About the per_page
# if you set it to true, it will load mathjax/katex script in each page (true 表示每一頁都加載js)
# if you set it to false, it will load mathjax/katex script according to your setting (add the 'mathjax: true' in page's front-matter)
# (false 需要時加載,須在使用的 Markdown Front-matter 加上 mathjax: true)
# MathJax
mathjax:
enable: false
per_page: false
# KaTeX
katex:
enable: false
per_page: false
hide_scrollbar: true
# Image (圖片設置)
# --------------------------------------
# Favicon網站圖標
favicon: /img/favicon.png
# Avatar (頭像)
avatar:
img: https://i.loli.net/2021/02/24/5O1day2nriDzjSu.png
effect: false
# Disable all banner image
disable_top_img: false
# The banner image of home page
index_img:
# If the banner of page not setting, it will show the top_img
default_top_img:
# The banner image of archive page
archive_img:
# If the banner of tag page not setting, it will show the top_img
# note: tag page, not tags page (子標籤頁面的 top_img)
tag_img:
# The banner image of tag page
# format:
# - tag name: xxxxx
tag_per_img:
# If the banner of category page not setting, it will show the top_img
# note: category page, not categories page (子分類頁面的 top_img)
category_img:
# The banner image of category page
# format:
# - category name: xxxxx
category_per_img:
cover:
# display the cover or not (是否顯示文章封面)
index_enable: true
aside_enable: true
archives_enable: true
# the position of cover in home page (封面顯示的位置)
# left/right/both
position: both
# When cover is not set, the default cover is displayed (當沒有設置cover時默認的封面顯示)
default_cover:
# - https://i.loli.net/2020/05/01/gkihqEjXxJ5UZ1C.jpg
# Replace Broken Images (替換無法顯示的圖片)
error_img:
flink: /img/friend_404.gif
post_page: /img/404.jpg
# A simple 404 page
error_404:
enable: false
subtitle: 'Page Not Found'
background: https://i.loli.net/2020/05/19/aKOcLiyPl2JQdFD.png
post_meta:
page: # Home Page
date_type: created # created or updated or both 主頁文章日期是創建日或者更新日或都顯示
date_format: date # date/relative 顯示日期還是相對日期
categories: true # true or false 主頁是否顯示分類
tags: false # true or false 主頁是否顯示標籤
label: true # true or false 顯示描述性文字
post:
date_type: both # created or updated or both 文章頁日期是創建日或者更新日或都顯示
date_format: date # date/relative 顯示日期還是相對日期
categories: true # true or false 文章頁是否顯示分類
tags: true # true or false 文章頁是否顯示標籤
label: true # true or false 顯示描述性文字
# wordcount (字數統計)
# see https://butterfly.js.org/posts/ceeb73f/#字數統計
wordcount:
enable: false
post_wordcount: true
min2read: true
total_wordcount: true
# Display the article introduction on homepage
# 1: description
# 2: both (if the description exists, it will show description, or show the auto_excerpt)
# 3: auto_excerpt (default)
# false: do not show the article introduction
index_post_content:
method: 3
length: 500 # if you set method to 2 or 3, the length need to config
# anchor
# when you scroll in post, the URL will update according to header id.
anchor: false
# Post
# --------------------------------------
# toc (目錄)
toc:
post: true
page: false
number: true
expand: false
style_simple: false # for post
post_copyright:
enable: true
decode: false
author_href:
license: CC BY-NC-SA 4.0
license_url: https://creativecommons.org/licenses/by-nc-sa/4.0/
# Sponsor/reward
reward:
enable: false
QR_code:
# - img: /img/wechat.jpg
# link:
# text: wechat
# - img: /img/alipay.jpg
# link:
# text: alipay
# Post edit
# Easily browse and edit blog source code online.
post_edit:
enable: false
# url: https://github.com/user-name/repo-name/edit/branch-name/subdirectory-name/
# For example: https://github.com/jerryc127/butterfly.js.org/edit/main/source/
url:
# Related Articles
related_post:
enable: true
limit: 6 # Number of posts displayed
date_type: created # or created or updated 文章日期顯示創建日或者更新日
# figcaption (圖片描述文字)
photofigcaption: false
# post_pagination (分頁)
# value: 1 || 2 || false
# 1: The 'next post' will link to old post
# 2: The 'next post' will link to new post
# false: disable pagination
post_pagination: 1
# Displays outdated notice for a post (文章過期提醒)
noticeOutdate:
enable: false
style: flat # style: simple/flat
limit_day: 500 # When will it be shown
position: top # position: top/bottom
message_prev: It has been
message_next: days since the last update, the content of the article may be outdated.
# Share System (分享功能)
# --------------------------------------
# AddThis
# https://www.addthis.com/
addThis:
enable: false
pubid:
# Share.js
# https://github.com/overtrue/share.js
sharejs:
enable: true
sites: facebook,twitter,wechat,weibo,qq
# AddToAny
# https://www.addtoany.com/
addtoany:
enable: false
item: facebook,twitter,wechat,sina_weibo,facebook_messenger,email,copy_link
# Comments System
# --------------------------------------
comments:
# Up to two comments system, the first will be shown as default
# Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42
use: # Valine,Disqus
text: true # Display the comment name next to the button
# lazyload: The comment system will be load when comment element enters the browser's viewport.
# If you set it to true, the comment count will be invalid
lazyload: false
count: false # Display comment count in post's top_img
card_post_count: false # Display comment count in Home Page
# disqus
# https://disqus.com/
disqus:
shortname:
apikey: # For newest comments widget
# Alternative Disqus - Render comments with Disqus API
# DisqusJS 評論系統,可以實現在網路審查地區載入 Disqus 評論列表,兼容原版
# https://github.com/SukkaW/DisqusJS
disqusjs:
shortname:
apikey:
option:
# livere (來必力)
# https://www.livere.com/
livere:
uid:
# gitalk
# https://github.com/gitalk/gitalk
gitalk:
client_id:
client_secret:
repo:
owner:
admin:
option:
# valine
# https://valine.js.org
valine:
appId: # leancloud application app id
appKey: # leancloud application app key
avatar: monsterid # gravatar style https://valine.js.org/#/avatar
serverURLs: # This configuration is suitable for domestic custom domain name users, overseas version will be automatically detected (no need to manually fill in)
bg: # valine background
visitor: false
option:
# waline - A simple comment system with backend support fork from Valine
# https://waline.js.org/
waline:
serverURL: # Waline server address url
bg: # waline background
pageview: false
option:
# utterances
# https://utteranc.es/
utterances:
repo:
# Issue Mapping: pathname/url/title/og:title
issue_term: pathname
# Theme: github-light/github-dark/github-dark-orange/icy-dark/dark-blue/photon-dark
light_theme: github-light
dark_theme: photon-dark
# Facebook Comments Plugin
# https://developers.facebook.com/docs/plugins/comments/
facebook_comments:
app_id:
user_id: # optional
pageSize: 10 # The number of comments to show
order_by: social # social/time/reverse_time
lang: en_US # Language en_US/zh_CN/zh_TW and so on
# Twikoo
# https://github.com/imaegoo/twikoo
twikoo:
envId:
region:
visitor: false
option:
# Giscus
# https://giscus.app/
giscus:
repo:
repo_id:
category_id:
theme:
light: light
dark: dark
option:
# Remark42
# https://remark42.com/docs/configuration/frontend/
remark42:
host: # Your Host URL
siteId: # Your Site ID
option:
# Chat Services
# --------------------------------------
# Chat Button [recommend]
# It will create a button in the bottom right corner of website, and hide the origin button
chat_btn: false
# The origin chat button is displayed when scrolling up, and the button is hidden when scrolling down
chat_hide_show: false
# chatra
# https://chatra.io/
chatra:
enable: false
id:
# tidio
# https://www.tidio.com/
tidio:
enable: false
public_key:
# daovoice
# http://daovoice.io/
daovoice:
enable: false
app_id:
# gitter
# https://gitter.im/
gitter:
enable: false
room:
# crisp
# https://crisp.chat/en/
crisp:
enable: false
website_id:
# Footer Settings
# --------------------------------------
footer:
owner:
enable: true
since: 2020
custom_text:
copyright: true # Copyright of theme and framework
# Analysis
# --------------------------------------
# Baidu Analytics
# https://tongji.baidu.com/web/welcome/login
baidu_analytics:
# Google Analytics
# https://analytics.google.com/analytics/web/
google_analytics:
# CNZZ Analytics
# https://www.umeng.com/
cnzz_analytics:
# Cloudflare Analytics
# https://www.cloudflare.com/zh-tw/web-analytics/
cloudflare_analytics:
# Microsoft Clarity
# https://clarity.microsoft.com/
microsoft_clarity:
# Advertisement
# --------------------------------------
# Google Adsense (谷歌廣告)
google_adsense:
enable: false
auto_ads: true
js: https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js
client:
enable_page_level_ads: true
# Insert ads manually (手動插入廣告)
# ad:
# index:
# aside:
# post:
# Verification (站長驗證)
# --------------------------------------
site_verification:
# - name: google-site-verification
# content: xxxxxx
# - name: baidu-site-verification
# content: xxxxxxx
# Beautify/Effect (美化/效果)
# --------------------------------------
# Theme color for customize
# Notice: color value must in double quotes like "#000" or may cause error!
# theme_color:
# enable: true
# main: "#49B1F5"
# paginator: "#00c4b6"
# button_hover: "#FF7242"
# text_selection: "#00c4b6"
# link_color: "#99a9bf"
# meta_color: "#858585"
# hr_color: "#A4D8FA"
# code_foreground: "#F47466"
# code_background: "rgba(27, 31, 35, .05)"
# toc_color: "#00c4b6"
# blockquote_padding_color: "#49b1f5"
# blockquote_background_color: "#49b1f5"
# scrollbar_color: "#49b1f5"
# meta_theme_color_light: "ffffff"
# meta_theme_color_dark: "#0d0d0d"
# The top_img settings of home page
# default: top img - full screen, site info - middle (默認top_img全屏site_info在中間)
# The position of site info, eg: 300px/300em/300rem/10% (主頁標題距離頂部距離)
index_site_info_top:
# The height of top_img, eg: 300px/300em/300rem (主頁top_img高度)
index_top_img_height:
# The user interface setting of category and tag page (category和tag頁的UI設置)
# index - same as Homepage UI (index 值代表 UI將與首頁的UI一樣)
# default - same as archives UI 默認跟archives頁面UI一樣
category_ui: # 留空或 index
tag_ui: # 留空或 index
# Website Background (設置網站背景)
# can set it to color or image (可設置圖片 或者 顔色)
# The formal of image: url(http://xxxxxx.com/xxx.jpg)
background:
# Footer Background
footer_bg: false
# the position of bottom right button/default unit: px (右下角按鈕距離底部的距離/默認單位為px)
rightside-bottom:
# Enter transitions (開啓網頁進入效果)
enter_transitions: true
# Background effects (背景特效)
# --------------------------------------
# canvas_ribbon (靜止彩帶背景)
# See: https://github.com/hustcc/ribbon.js
canvas_ribbon:
enable: false
size: 150
alpha: 0.6
zIndex: -1
click_to_change: false
mobile: false
# Fluttering Ribbon (動態彩帶)
canvas_fluttering_ribbon:
enable: false
mobile: false
# canvas_nest
# https://github.com/hustcc/canvas-nest.js
canvas_nest:
enable: false
color: '0,0,255' #color of lines, default: '0,0,0'; RGB values: (R,G,B).(note: use ',' to separate.)
opacity: 0.7 # the opacity of line (0~1), default: 0.5.
zIndex: -1 # z-index property of the background, default: -1.
count: 99 # the number of lines, default: 99.
mobile: false
# Typewriter Effect (打字效果)
# https://github.com/disjukr/activate-power-mode
activate_power_mode:
enable: false
colorful: true # open particle animation (冒光特效)
shake: true # open shake (抖動特效)
mobile: false
# Mouse click effects: fireworks (鼠標點擊效果: 煙火特效)
fireworks:
enable: false
zIndex: 9999 # -1 or 9999
mobile: false
# Mouse click effects: Heart symbol (鼠標點擊效果: 愛心)
click_heart:
enable: false
mobile: false
# Mouse click effects: words (鼠標點擊效果: 文字)
ClickShowText:
enable: false
text:
# - I
# - LOVE
# - YOU
fontSize: 15px
random: false
mobile: false
# Default display mode (網站默認的顯示模式)
# light (default) / dark
display_mode: light
# Beautify (美化頁面顯示)
beautify:
enable: false
field: post # site/post
title-prefix-icon: # '\f0c1'
title-prefix-icon-color: # '#F47466'
# Global font settings
# Don't modify the following settings unless you know how they work (非必要不要修改)
font:
global-font-size:
code-font-size:
font-family:
code-font-family:
# Font settings for the site title and site subtitle
# 左上角網站名字 主頁居中網站名字
blog_title_font:
font_link:
font-family:
# The setting of divider icon (水平分隔線圖標設置)
hr_icon:
enable: true
icon: # the unicode value of Font Awesome icon, such as '\3423'
icon-top:
# the subtitle on homepage (主頁subtitle)
subtitle:
enable: false
# Typewriter Effect (打字效果)
effect: true
# loop (循環打字)
loop: true
# source 調用第三方服務
# source: false 關閉調用
# source: 1 調用一言網的一句話(簡體) https://hitokoto.cn/
# source: 2 調用一句網(簡體) http://yijuzhan.com/
# source: 3 調用今日詩詞(簡體) https://www.jinrishici.com/
# subtitle 會先顯示 source , 再顯示 sub 的內容
source: false
# 如果關閉打字效果subtitle 只會顯示 sub 的第一行文字
sub:
# Loading Animation (加載動畫)
preloader: false
# aside (側邊欄)
# --------------------------------------
aside:
enable: true
hide: false
button: true
mobile: true # display on mobile
position: right # left or right
display:
archive: true
tag: true
category: true
card_author:
enable: true
description:
button:
enable: true
icon: fab fa-github
text: Follow Me
link: https://github.com/xxxxxx
card_announcement:
enable: true
content: This is my Blog
card_recent_post:
enable: true
limit: 5 # if set 0 will show all
sort: date # date or updated
sort_order: # Don't modify the setting unless you know how it works
card_categories:
enable: true
limit: 8 # if set 0 will show all
expand: none # none/true/false
sort_order: # Don't modify the setting unless you know how it works
card_tags:
enable: true
limit: 40 # if set 0 will show all
color: false
sort_order: # Don't modify the setting unless you know how it works
card_archives:
enable: true
type: monthly # yearly or monthly
format: MMMM YYYY # eg: YYYY年MM月
order: -1 # Sort of order. 1, asc for ascending; -1, desc for descending
limit: 8 # if set 0 will show all
sort_order: # Don't modify the setting unless you know how it works
card_webinfo:
enable: true
post_count: true
last_push_date: true
sort_order: # Don't modify the setting unless you know how it works
# busuanzi count for PV / UV in site
# 訪問人數
busuanzi:
site_uv: true
site_pv: true
page_pv: true
# Time difference between publish date and now (網頁運行時間)
# Formal: Month/Day/Year Time or Year/Month/Day Time
runtimeshow:
enable: false
publish_date:
# Aside widget - Newest Comments
newest_comments:
enable: false
sort_order: # Don't modify the setting unless you know how it works
limit: 6
storage: 10 # unit: mins, save data to localStorage
avatar: true
# Bottom right button (右下角按鈕)
# --------------------------------------
# Conversion between Traditional and Simplified Chinese (簡繁轉換)
translate:
enable: false
# The text of a button
default:
# the language of website (1 - Traditional Chinese/ 2 - Simplified Chinese
defaultEncoding: 2
# Time delay
translateDelay: 0
# The text of the button when the language is Simplified Chinese
msgToTraditionalChinese: '繁'
# The text of the button when the language is Traditional Chinese
msgToSimplifiedChinese: '簡'
# Read Mode (閲讀模式)
readmode: true
# dark mode
darkmode:
enable: true
# Toggle Button to switch dark/light mode
button: true
# Switch dark/light mode automatically (自動切換 dark mode和 light mode)
# autoChangeMode: 1 Following System Settings, if the system doesn't support dark mode, it will switch dark mode between 6 pm to 6 am
# autoChangeMode: 2 Switch dark mode between 6 pm to 6 am
# autoChangeMode: false
autoChangeMode: false
# Don't modify the following settings unless you know how they work (非必要請不要修改 )
# Choose: readmode,translate,darkmode,hideAside,toc,chat,comment
# Don't repeat 不要重複
rightside_item_order:
enable: false
hide: # readmode,translate,darkmode,hideAside
show: # toc,chat,comment
# Lightbox (圖片大圖查看模式)
# --------------------------------------
# You can only choose one, or neither (只能選擇一個 或者 兩個都不選)
# medium-zoom
# https://github.com/francoischalifour/medium-zoom
medium_zoom: false
# fancybox
# http://fancyapps.com/fancybox/3/
fancybox: true
# Tag Plugins settings (標籤外掛)
# --------------------------------------
# mermaid
# see https://github.com/mermaid-js/mermaid
mermaid:
enable: false
# built-in themes: default/forest/dark/neutral
theme:
light: default
dark: dark
# Note (Bootstrap Callout)
note:
# Note tag style values:
# - simple bs-callout old alert style. Default.
# - modern bs-callout new (v2-v3) alert style.
# - flat flat callout style with background, like on Mozilla or StackOverflow.
# - disabled disable all CSS styles import of note tag.
style: flat
icons: true
border_radius: 3
# Offset lighter of background in % for modern and flat styles (modern: -12 | 12; flat: -18 | 6).
# Offset also applied to label tag variables. This option can work with disabled note tag.
light_bg_offset: 0
# other
# --------------------------------------
# Pjax
# It may contain bugs and unstable, give feedback when you find the bugs.
# https://github.com/MoOx/pjax
pjax:
enable: false
exclude:
# - xxxx
# - xxxx
# Inject the css and script (aplayer/meting)
aplayerInject:
enable: false
per_page: true
# Snackbar (Toast Notification 彈窗)
# https://github.com/polonel/SnackBar
# position 彈窗位置
# 可選 top-left / top-center / top-right / bottom-left / bottom-center / bottom-right
snackbar:
enable: false
position: bottom-left
bg_light: '#49b1f5' # The background color of Toast Notification in light mode
bg_dark: '#1f1f1f' # The background color of Toast Notification in dark mode
# https://instant.page/
# prefetch (預加載)
instantpage: false
# https://github.com/vinta/pangu.js
# Insert a space between Chinese character and English character (中英文之間添加空格)
pangu:
enable: false
field: site # site/post
# Lazyload (圖片懶加載)
# https://github.com/verlok/vanilla-lazyload
lazyload:
enable: false
field: site # site/post
placeholder:
blur: false
# PWA
# See https://github.com/JLHwung/hexo-offline
# ---------------
# pwa:
# enable: false
# manifest: /pwa/manifest.json
# apple_touch_icon: /pwa/apple-touch-icon.png
# favicon_32_32: /pwa/32.png
# favicon_16_16: /pwa/16.png
# mask_icon: /pwa/safari-pinned-tab.svg
# Open graph meta tags
# https://developers.facebook.com/docs/sharing/webmasters/
Open_Graph_meta: true
# Add the vendor prefixes to ensure compatibility
css_prefix: true
# Inject
# Insert the code to head (before '</head>' tag) and the bottom (before '</body>' tag)
# 插入代码到头部 </head> 之前 和 底部 </body> 之前
inject:
head:
# - <link rel="stylesheet" href="/xxx.css">
bottom:
# - <script src="xxxx"></script>
# CDN
# Don't modify the following settings unless you know how they work
# 非必要請不要修改
CDN:
# The CDN provider of internal scripts (主題內部 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# Dev version can only choose. ( dev版的主題只能設置為 local )
internal_provider: local
# The CDN provider of third party scripts (第三方 js 的 cdn 配置)
# option: local/jsdelivr/unpkg/cdnjs/custom
# when set it to local, you need to install hexo-butterfly-extjs
third_party_provider: jsdelivr
# Add version number to CDN, true or false
version: false
# Custom format
# For example: https://cdn.staticfile.org/${cdnjs_name}/${version}/${min_cdnjs_file}
custom_format:
option:
# main_css:
# main:
# utils:
# translate:
# local_search:
# algolia_js:
# algolia_search_v4:
# instantsearch_v4:
# pjax:
# gitalk:
# gitalk_css:
# blueimp_md5:
# valine:
# disqusjs:
# disqusjs_css:
# twikoo:
# waline_js:
# waline_css:
# sharejs:
# sharejs_css:
# mathjax:
# katex:
# katex_copytex:
# mermaid:
# canvas_ribbon:
# canvas_fluttering_ribbon:
# canvas_nest:
# lazyload:
# instantpage:
# typed:
# pangu:
# fancybox_css_v4:
# fancybox_v4:
# medium_zoom:
# snackbar_css:
# snackbar:
# activate_power_mode:
# fireworks:
# click_heart:
# ClickShowText:
# fontawesomeV6:
# flickr_justified_gallery_js:
# flickr_justified_gallery_css:
# aplayer_css:
# aplayer_js:
# meting_js:
# prismjs_js:
# prismjs_lineNumber_js:
# prismjs_autoloader:

View File

@ -0,0 +1,121 @@
footer:
framework: Framework
theme: Theme
copy:
success: Copy successfully
error: Copy error
noSupport: The browser does not support
page:
articles: Articles
tag: Tag
category: Category
archives: Archives
card_post_count: comments
sticky: Sticky
no_title: No title
post:
created: Created
updated: Updated
wordcount: Word count
min2read: Reading time
min2read_unit: min
page_pv: Post View
comments: Comments
copyright:
author: Author
link: Link
copyright_notice: Copyright Notice
copyright_content: 'All articles in this blog are licensed under <a href="%s">%s</a> unless stating additionally.'
recommend: Related Articles
edit: Edited on
search:
title: Search
load_data: Loading the Database
algolia_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}."
hits_stats: '${hits} results found in ${time} ms'
local_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
pagination:
prev: Previous Post
next: Next Post
comment: Comment
aside:
articles: Articles
tags: Tags
categories: Categories
card_announcement: Announcement
card_categories: Categories
card_tags: Tags
card_archives: Archives
card_recent_post: Recent Post
card_webinfo:
headline: Info
article_name: Article
runtime:
name: Run time
unit: days
last_push_date:
name: Last Push
site_wordcount: Total Count
site_uv_name: UV
site_pv_name: PV
more_button: More
card_newest_comments:
headline: Newest Comments
loading_text: loading...
error: Unable to get the data, please make sure the settings are correct.
zero: No Comment
image: image
link: link
code: code
card_toc: Catalog
date_suffix:
just: Just
min: minutes ago
hour: hours ago
day: days ago
month: months ago
donate: Donate
share: Share
rightside:
readmode_title: Read Mode
translate_title: Toggle Between Traditional Chinese And Simplified Chinese
night_mode_title: Toggle Between Light And Dark Mode
back_to_top: Back To Top
toc: Table Of Contents
scroll_to_comment: Scroll To Comments
setting: Setting
aside: Toggle between single-column and double-column
chat: Chat
copy_copyright:
author: Author
link: Link
source: Source
info: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
Snackbar:
chs_to_cht: Traditional Chinese Activated Manually
cht_to_chs: Simplified Chinese Activated Manually
day_to_night: Dark Mode Activated Manually
night_to_day: Light Mode Activated Manually
loading: Loading...
error404: Page not found

View File

@ -0,0 +1,121 @@
footer:
framework: Framework
theme: Theme
copy:
success: Copy successfully
error: Copy error
noSupport: The browser does not support
page:
articles: Articles
tag: Tag
category: Category
archives: Archives
card_post_count: comments
sticky: Sticky
no_title: No title
post:
created: Created
updated: Updated
wordcount: Word count
min2read: Reading time
min2read_unit: min
page_pv: Post View
comments: Comments
copyright:
author: Author
link: Link
copyright_notice: Copyright Notice
copyright_content: 'All articles in this blog are licensed under <a href="%s">%s</a> unless stating additionally.'
recommend: Related Articles
edit: Edited on
search:
title: Search
load_data: Loading the Database
algolia_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}."
hits_stats: '${hits} results found in ${time} ms'
local_search:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
pagination:
prev: Previous Post
next: Next Post
comment: Comment
aside:
articles: Articles
tags: Tags
categories: Categories
card_announcement: Announcement
card_categories: Categories
card_tags: Tags
card_archives: Archives
card_recent_post: Recent Post
card_webinfo:
headline: Info
article_name: Article
runtime:
name: Run time
unit: days
last_push_date:
name: Last Push
site_wordcount: Total Count
site_uv_name: UV
site_pv_name: PV
more_button: More
card_newest_comments:
headline: Newest Comments
loading_text: loading...
error: Unable to get the data, please make sure the settings are correct.
zero: No Comment
image: image
link: link
code: code
card_toc: Catalog
date_suffix:
just: Just
min: minutes ago
hour: hours ago
day: days ago
month: months ago
donate: Donate
share: Share
rightside:
readmode_title: Read Mode
translate_title: Switch Between Traditional Chinese And Simplified Chinese
night_mode_title: Switch Between Light And Dark Mode
back_to_top: Back To Top
toc: Table Of Contents
scroll_to_comment: Scroll To Comments
setting: Setting
aside: Toggle between single-column and double-column
chat: Chat
copy_copyright:
author: Author
link: Link
source: Source
info: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
Snackbar:
chs_to_cht: Traditional Chinese Activated Manually
cht_to_chs: Simplified Chinese Activated Manually
day_to_night: Dark Mode Activated Manually
night_to_day: Light Mode Activated Manually
loading: Loading...
error404: Page not found

View File

@ -0,0 +1,122 @@
footer:
framework: 框架
theme: 主题
copy:
success: 复制成功
error: 复制错误
noSupport: 浏览器不支持
page:
articles: 文章总览
tag: 标签
category: 分类
archives: 归档
card_post_count: 条评论
sticky: 置顶
no_title: 无题
post:
created: 发表于
updated: 更新于
wordcount: 字数总计
min2read: 阅读时长
min2read_unit: 分钟
page_pv: 阅读量
comments: 评论数
copyright:
author: 文章作者
link: 文章链接
copyright_notice: 版权声明
copyright_content: '本博客所有文章除特别声明外,均采用
<a href="%s" target="_blank">%s</a> 许可协议。转载请注明来自 <a href="%s" target="_blank">%s</a>'
recommend: 相关推荐
edit: 编辑
search:
title: 搜索
load_data: 数据库加载中
algolia_search:
input_placeholder: 搜索文章
hits_empty: '找不到您查询的内容:${query}'
hits_stats: '找到 ${hits} 条结果,用时 ${time} 毫秒'
local_search:
input_placeholder: 搜索文章
hits_empty: '找不到您查询的内容:${query}'
pagination:
prev: 上一篇
next: 下一篇
comment: 评论
aside:
articles: 文章
tags: 标签
categories: 分类
card_announcement: 公告
card_categories: 分类
card_tags: 标签
card_archives: 归档
card_recent_post: 最新文章
card_webinfo:
headline: 网站资讯
article_name: 文章数目
runtime:
name: 已运行时间
unit:
last_push_date:
name: 最后更新时间
site_wordcount: 本站总字数
site_uv_name: 本站访客数
site_pv_name: 本站总访问量
more_button: 查看更多
card_newest_comments:
headline: 最新评论
loading_text: 正在加载中...
error: 无法获取评论,请确认相关配置是否正确
zero: 没有评论
image: 图片
link: 链接
code: 代码
card_toc: 目录
date_suffix:
just: 刚刚
min: 分钟前
hour: 小时前
day: 天前
month: 个月前
donate: 打赏
share: 分享
rightside:
readmode_title: 阅读模式
translate_title: 简繁转换
night_mode_title: 浅色和深色模式转换
back_to_top: 回到顶部
toc: 目录
scroll_to_comment: 直达评论
setting: 设置
aside: 单栏和双栏切换
chat: 聊天
copy_copyright:
author: 作者
link: 链接
source: 来源
info: 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Snackbar:
chs_to_cht: 你已切换为繁体
cht_to_chs: 你已切换为简体
day_to_night: 你已切换为深色模式
night_to_day: 你已切换为浅色模式
loading: 加载中...
error404: 页面没有找到

View File

@ -0,0 +1,122 @@
footer:
framework: 框架
theme: 主題
copy:
success: 複製成功
error: 複製錯誤
noSupport: 瀏覽器不支援
page:
articles: 文章總覽
tag: 標籤
category: 分類
archives: 歸檔
card_post_count: 條評論
sticky: 置頂
no_title: 無題
post:
created: 發表於
updated: 更新於
wordcount: 字數總計
min2read: 閱讀時長
min2read_unit: 分鐘
page_pv: 閱讀量
comments: 評論數
copyright:
author: 文章作者
link: 文章連結
copyright_notice: 版權聲明
copyright_content: '本部落格所有文章除特別聲明外,均採用
<a href="%s" target="_blank">%s</a> 許可協議。轉載請註明來自 <a href="%s" target="_blank">%s</a>'
recommend: 相關推薦
edit: 編輯
search:
title: 搜尋
load_data: 資料庫載入中
algolia_search:
input_placeholder: 搜尋文章
hits_empty: '找不到您查詢的內容:${query}'
hits_stats: '找到 ${hits} 條結果,用時 ${time} 毫秒'
local_search:
input_placeholder: 搜尋文章
hits_empty: '找不到您查詢的內容:${query}'
pagination:
prev: 上一篇
next: 下一篇
comment: 評論
aside:
articles: 文章
tags: 標籤
categories: 分類
card_announcement: 公告
card_categories: 分類
card_tags: 標籤
card_archives: 歸檔
card_recent_post: 最新文章
card_webinfo:
headline: 網站資訊
article_name: 文章數目
runtime:
name: 已執行時間
unit:
last_push_date:
name: 最後更新時間
site_wordcount: 本站總字數
site_uv_name: 本站訪客數
site_pv_name: 本站總訪問量
more_button: 檢視更多
card_newest_comments:
headline: 最新評論
loading_text: 正在載入中...
error: 無法獲取評論,請確認相關配置是否正確
zero: 沒有評論
image: 圖片
link: 連結
code: 程式碼
card_toc: 目錄
date_suffix:
just: 剛剛
min: 分鐘前
hour: 小時前
day: 天前
month: 個月前
donate: 打賞
share: 分享
rightside:
readmode_title: 閱讀模式
translate_title: 簡繁轉換
night_mode_title: 淺色和深色模式轉換
back_to_top: 回到頂部
toc: 目錄
scroll_to_comment: 直達評論
setting: 設定
aside: 單欄和雙欄切換
chat: 聊天
copy_copyright:
author: 作者
link: 連結
source: 來源
info: 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
Snackbar:
chs_to_cht: 你已切換為繁體
cht_to_chs: 你已切換為簡體
day_to_night: 你已切換為深色模式
night_to_day: 你已切換為淺色模式
loading: 載入中...
error404: 頁面沒有找到

View File

@ -0,0 +1,9 @@
extends includes/layout.pug
block content
include ./includes/mixins/article-sort.pug
#archive
- const archiveLength = findArchiveLength(fragment_cache)
.article-sort-title= _p('page.articles') + ' - ' + archiveLength
+articleSort(page.posts)
include includes/pagination.pug

View File

@ -0,0 +1,14 @@
extends includes/layout.pug
block content
if theme.category_ui == 'index'
include ./includes/mixins/post-ui.pug
#recent-posts.recent-posts.category_ui
+postUI
include includes/pagination.pug
else
include ./includes/mixins/article-sort.pug
#category
.article-sort-title= _p('page.category') + ' - ' + page.category
+articleSort(page.posts)
include includes/pagination.pug

View File

@ -0,0 +1,12 @@
- var top_img_404 = theme.error_404.background || theme.default_top_img
#body-wrap.error404
include ./header/index.pug
#error-wrap
.error-content
.error-img
img(src=url_for(top_img_404) alt='Page not found')
.error-info
h1.error_title= '404'
.error_subtitle= theme.error_404.subtitle || _p('error404')

View File

@ -0,0 +1,72 @@
div
script(src=url_for(theme.asset.utils))
script(src=url_for(theme.asset.main))
if theme.translate.enable
script(src=url_for(theme.asset.translate))
if theme.medium_zoom
script(src=url_for(theme.asset.medium_zoom))
else if theme.fancybox
script(src=url_for(theme.asset.fancybox_v4))
if theme.instantpage
script(src=url_for(theme.asset.instantpage), type='module')
if theme.lazyload.enable
script(src=url_for(theme.asset.lazyload))
if theme.snackbar.enable
script(src=url_for(theme.asset.snackbar))
if theme.pangu.enable
!= partial("includes/third-party/pangu.pug", {}, { cache: true })
//- search
if theme.algolia_search.enable
script(src=url_for(theme.asset.algolia_search_v4))
script(src=url_for(theme.asset.instantsearch_v4))
script(src=url_for(theme.asset.algolia_js))
else if theme.local_search.enable
script(src=url_for(theme.asset.local_search))
if theme.preloader
!= partial("includes/loading/loading-js", {}, { cache: true })
.js-pjax
if needLoadCountJs
!= partial("includes/third-party/card-post-count/index", {}, { cache: true })
if loadSubJs
include ./third-party/subtitle.pug
include ./third-party/math/index.pug
if commentsJsLoad
include ./third-party/comments/js.pug
!= partial("includes/third-party/prismjs", {}, { cache: true })
if theme.aside.enable && theme.newest_comments.enable
if theme.pjax.enable
!= partial("includes/third-party/newest-comments/index", {}, { cache: true })
else if (!is_post() && page.aside !== false)
!= partial("includes/third-party/newest-comments/index", {}, { cache: true })
!= fragment_cache('injectBottom', function(){return injectHtml(theme.inject.bottom)})
!= partial("includes/third-party/effect", {}, { cache: true })
!= partial("includes/third-party/chat/index", {}, { cache: true })
if theme.aplayerInject && theme.aplayerInject.enable
if theme.pjax.enable || theme.aplayerInject.per_page
include ./third-party/aplayer.pug
else if page.aplayer
include ./third-party/aplayer.pug
if theme.pjax.enable
!= partial("includes/third-party/pjax", {}, { cache: true })
if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv
script(async data-pjax src='//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js')

View File

@ -0,0 +1,17 @@
#footer-wrap
if theme.footer.owner.enable
- var now = new Date()
- var nowYear = now.getFullYear()
if theme.footer.owner.since && theme.footer.owner.since != nowYear
.copyright!= `&copy;${theme.footer.owner.since} - ${nowYear} By ${config.author}`
else
.copyright!= `&copy;${nowYear} By ${config.author}`
if theme.footer.copyright
.framework-info
span= _p('footer.framework') + ' '
a(href='https://hexo.io')= 'Hexo'
span.footer-separator |
span= _p('footer.theme') + ' '
a(href='https://github.com/jerryc127/hexo-theme-butterfly')= 'Butterfly'
if theme.footer.custom_text
.footer_custom_text!=`${theme.footer.custom_text}`

View File

@ -0,0 +1,76 @@
- var pageTitle
- is_archive() ? page.title = findArchivesTitle(page, theme.menu, date) : ''
- if (is_tag()) pageTitle = _p('page.tag') + ': ' + page.tag
- else if (is_category()) pageTitle = _p('page.category') + ': ' + page.category
- else if (is_current('/404.html', [strict])) pageTitle = _p('error404')
- else pageTitle = page.title || config.title || ''
- var isSubtitle = config.subtitle ? ' - ' + config.subtitle : ''
- var tabTitle = is_home() || !pageTitle ? config.title + isSubtitle : pageTitle + ' | ' + config.title
- var pageKeywords
- if (page.keywords) pageKeywords = Array.isArray(page.keywords) ? (page.keywords).join(',') : ([]).join(',') || page.keywords
- else if (page.tags && page.tags.length) pageKeywords = page.tags.data.map(function(tag) {return tag.name;}).join(',')
- else pageKeywords = Array.isArray(config.keywords) ? (config.keywords).join(','): ([]).join(',') || config.keywords
- var pageAuthor = config.email ? config.author + ',' + config.email : config.author
- var pageCopyright = config.copyright || config.author
- var themeColorLight = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_light || '#ffffff'
- var themeColorDark = theme.theme_color && theme.theme_color.enable && theme.theme_color.meta_theme_color_dark || '#0d0d0d'
- var themeColor = theme.display_mode === 'dark' ? themeColorDark : themeColorLight
meta(charset='UTF-8')
meta(http-equiv="X-UA-Compatible" content="IE=edge")
meta(name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no")
title= tabTitle
if pageKeywords
meta(name="keywords" content=pageKeywords)
meta(name="author" content=pageAuthor)
meta(name="copyright" content=pageCopyright)
meta(name ="format-detection" content="telephone=no")
meta(name="theme-color" content=themeColor)
//- Open_Graph
include ./head/Open_Graph.pug
!=favicon_tag(theme.favicon || config.favicon)
link(rel="canonical" href=urlNoIndex())
//- 預解析
!=partial('includes/head/preconnect', {}, {cache: true})
//- 網站驗證
!=partial('includes/head/site_verification', {}, {cache: true})
//- PWA
if (theme.pwa && theme.pwa.enable)
!=partial('includes/head/pwa', {}, {cache: true})
//- main css
link(rel='stylesheet', href=url_for(theme.asset.main_css))
link(rel='stylesheet', href=url_for(theme.asset.fontawesomeV6) media="print" onload="this.media='all'")
if (theme.snackbar && theme.snackbar.enable)
link(rel='stylesheet', href=url_for(theme.asset.snackbar_css) media="print" onload="this.media='all'")
if theme.fancybox
link(rel='stylesheet' href=url_for(theme.asset.fancybox_css_v4) media="print" onload="this.media='all'")
//- google_adsense
!=partial('includes/head/google_adsense', {}, {cache: true})
//- analytics
!=partial('includes/head/analytics', {}, {cache: true})
//- font
if theme.blog_title_font && theme.blog_title_font.font_link
link(rel='stylesheet' href=url_for(theme.blog_title_font.font_link) media="print" onload="this.media='all'")
//- global config
!=partial('includes/head/config', {}, {cache: true})
include ./head/config_site.pug
include ./head/noscript.pug
!=fragment_cache('injectHeadJs', function(){return inject_head_js()})
!=fragment_cache('injectHead', function(){return injectHtml(theme.inject.head)})

View File

@ -0,0 +1,11 @@
if theme.Open_Graph_meta
- let contentType = is_post() ? 'article' : 'website'
- let metaImage = (page.cover || theme.avatar.img) ? full_url_for(page.cover || theme.avatar.img) : ''
- let fb_appId = theme.facebook_comments.app_id || ''
- let fb_admins = theme.facebook_comments.user_id || ''
!= open_graph({type: contentType, image: metaImage, fb_admins: fb_admins, fb_app_id: fb_appId})
else
meta(name="description" content=page_description())

View File

@ -0,0 +1,31 @@
if theme.baidu_analytics
script.
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?!{theme.baidu_analytics}";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
if theme.google_analytics
script(async src=`https://www.googletagmanager.com/gtag/js?id=${theme.google_analytics}`)
script.
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '!{theme.google_analytics}');
if theme.cnzz_analytics
script(async data-pjax src=`https://s4.cnzz.com/z_stat.php?id=${theme.cnzz_analytics}&web_id=${theme.cnzz_analytics}`)
if theme.cloudflare_analytics
script(defer data-pjax src='https://static.cloudflareinsights.com/beacon.min.js' data-cf-beacon=`{"token": "${theme.cloudflare_analytics}"}`)
if theme.microsoft_clarity
script.
(function(c,l,a,r,i,t,y){
c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "!{theme.microsoft_clarity}");

View File

@ -0,0 +1,124 @@
-
let algolia = 'undefined';
let env = process.env;
if (theme.algolia_search.enable) {
algolia = JSON.stringify({
appId: env.ALGOLIA_APP_ID || config.algolia.appId || config.algolia.applicationID,
apiKey: env.ALGOLIA_API_KEY || config.algolia.apiKey,
indexName: env.ALGOLIA_INDEX_NAME || config.algolia.indexName,
hits: theme.algolia_search.hits,
// search languages
languages: {
input_placeholder: _p("search.algolia_search.input_placeholder"),
hits_empty: _p("search.algolia_search.hits_empty"),
hits_stats: _p("search.algolia_search.hits_stats"),
}
})
}
let localSearch = 'undefined';
if (theme.local_search && theme.local_search.enable) {
localSearch = JSON.stringify({
path: theme.local_search.CDN ? theme.local_search.CDN : config.root + config.search.path,
preload: theme.local_search.preload,
languages: {
// search languages
hits_empty: _p("search.local_search.hits_empty"),
}
})
}
let translate = 'undefined';
if (theme.translate && theme.translate.enable){
translate = JSON.stringify({
defaultEncoding: theme.translate.defaultEncoding,
translateDelay: theme.translate.translateDelay,
msgToTraditionalChinese: theme.translate.msgToTraditionalChinese,
msgToSimplifiedChinese: theme.translate.msgToSimplifiedChinese
})
}
let copyright = 'undefined';
if (theme.copy.enable && theme.copy.copyright.enable){
copyright = JSON.stringify({
limitCount: theme.copy.copyright.limit_count,
languages: {
author: _p("copy_copyright.author") + ': ' + config.author,
link: _p("copy_copyright.link") + ': ',
source: _p("copy_copyright.source") + ': ' + config.title,
info: _p("copy_copyright.info")
}
})
}
let Snackbar = 'undefined';
if (theme.snackbar && theme.snackbar.enable) {
Snackbar = JSON.stringify({
chs_to_cht: _p("Snackbar.chs_to_cht"),
cht_to_chs: _p("Snackbar.cht_to_chs"),
day_to_night: _p("Snackbar.day_to_night"),
night_to_day: _p("Snackbar.night_to_day"),
bgLight: theme.snackbar.bg_light,
bgDark: theme.snackbar.bg_dark,
position: theme.snackbar.position,
})
}
let noticeOutdate = 'undefined';
if (theme.noticeOutdate && theme.noticeOutdate.enable) {
noticeOutdate = JSON.stringify({
limitDay: theme.noticeOutdate.limit_day,
position: theme.noticeOutdate.position,
messagePrev: theme.noticeOutdate.message_prev,
messageNext: theme.noticeOutdate.message_next,
})
}
let highlight = 'undefined';
if ((config.highlight && config.highlight.enable) || (config.prismjs && config.prismjs.enable)) {
highlight = JSON.stringify({
plugin: config.highlight.enable ? 'highlighjs' : 'prismjs',
highlightCopy: theme.highlight_copy,
highlightLang: theme.highlight_lang,
highlightHeightLimit: theme.highlight_height_limit
})
}
script.
const GLOBAL_CONFIG = {
root: '!{config.root}',
algolia: !{algolia},
localSearch: !{localSearch},
translate: !{translate},
noticeOutdate: !{noticeOutdate},
highlight: !{highlight},
copy: {
success: '!{_p("copy.success")}',
error: '!{_p("copy.error")}',
noSupport: '!{_p("copy.noSupport")}'
},
relativeDate: {
homepage: !{theme.post_meta.page.date_format === 'relative'},
post: !{theme.post_meta.post.date_format === 'relative'}
},
runtime: '!{theme.runtimeshow.enable ? _p("aside.card_webinfo.runtime.unit") : ""}',
date_suffix: {
just: '!{_p("date_suffix.just")}',
min: '!{_p("date_suffix.min")}',
hour: '!{_p("date_suffix.hour")}',
day: '!{_p("date_suffix.day")}',
month: '!{_p("date_suffix.month")}'
},
copyright: !{copyright},
lightbox: '!{ theme.medium_zoom ? "mediumZoom" : (theme.fancybox ? "fancybox" : "null" )}',
Snackbar: !{Snackbar},
source: {
justifiedGallery: {
js: '!{url_for(theme.asset.flickr_justified_gallery_js)}',
css: '!{url_for(theme.asset.flickr_justified_gallery_css)}'
}
},
isPhotoFigcaption: !{theme.photofigcaption},
islazyload: !{theme.lazyload.enable},
isAnchor: !{theme.anchor}
}

View File

@ -0,0 +1,30 @@
-
const titleVal = pageTitle.replace(/'/ig,"\\'")
let isHighlightShrink
if (theme.highlight_shrink == 'none') isHighlightShrink = 'undefined'
else if (page.highlight_shrink === true || page.highlight_shrink === false) isHighlightShrink = page.highlight_shrink
else isHighlightShrink = theme.highlight_shrink
var showToc = false
if (theme.aside.enable && page.aside !== false) {
let tocEnable = false
if (is_post()) {
if (theme.toc.post) tocEnable = true
} else if (is_page()) {
if (theme.toc.page) tocEnable = true
}
const pageToc = page.toc === true || page.toc === false ? page.toc : tocEnable
showToc = pageToc && (toc(page.content) !== '' || page.encrypt == true )
}
-
script#config-diff.
var GLOBAL_CONFIG_SITE = {
title: '!{titleVal}',
isPost: !{is_post()},
isHome: !{is_home()},
isHighlightShrink: !{isHighlightShrink},
isToc: !{showToc},
postUpdate: '!{full_date(page.updated)}'
}

View File

@ -0,0 +1,9 @@
if (theme.google_adsense && theme.google_adsense.enable)
script(async src=theme.google_adsense.js)
if theme.google_adsense.auto_ads
script.
(adsbygoogle = window.adsbygoogle || []).push({
google_ad_client: '!{theme.google_adsense.client}',
enable_page_level_ads: '!{theme.google_adsense.enable_page_level_ads}'
});

View File

@ -0,0 +1,14 @@
noscript.
<style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style>

View File

@ -0,0 +1,22 @@
link(rel="preconnect" href="//cdn.jsdelivr.net")
if theme.google_analytics
link(rel="preconnect" href="//www.google-analytics.com" crossorigin='')
if theme.baidu_analytics
link(rel="preconnect" href="//hm.baidu.com")
if theme.cnzz_analytics
link(rel="preconnect" href="//s4.cnzz.com")
if theme.cloudflare_analytics
link(rel="preconnect" href="//static.cloudflareinsights.com")
if theme.microsoft_clarity
link(rel="preconnect" href="//www.clarity.ms")
if theme.blog_title_font && theme.blog_title_font.font_link && theme.blog_title_font.font_link.indexOf('//fonts.googleapis.com') != -1
link(rel="preconnect" href="//fonts.googleapis.com" crossorigin='')
if theme.busuanzi.site_uv || theme.busuanzi.site_pv || theme.busuanzi.page_pv
link(rel="preconnect" href="//busuanzi.ibruce.info")

View File

@ -0,0 +1,11 @@
link(rel="manifest" href=url_for(theme.pwa.manifest))
if(theme.pwa.theme_color)
meta(name="msapplication-TileColor" content=theme.pwa.theme_color)
if(theme.pwa.apple_touch_icon)
link(rel="apple-touch-icon" sizes="180x180" href=url_for(theme.pwa.apple_touch_icon))
if(theme.pwa.favicon_32_32)
link(rel="icon" type="image/png" sizes="32x32" href=url_for(theme.pwa.favicon_32_32))
if(theme.pwa.favicon_16_16)
link(rel="icon" type="image/png" sizes="16x16" href=url_for(theme.pwa.favicon_16_16))
if(theme.pwa.mask_icon)
link(rel="mask-icon" href=url_for(theme.pwa.mask_icon) color="#5bbad5")

View File

@ -0,0 +1,3 @@
if theme.site_verification
each item in theme.site_verification
meta(name=item.name content=item.content)

View File

@ -0,0 +1,50 @@
if !theme.disable_top_img && page.top_img !== false
if is_post()
- var top_img = page.top_img || page.cover || page.randomcover
else if is_page()
- var top_img = page.top_img || theme.default_top_img
else if is_tag()
- var top_img = theme.tag_per_img && theme.tag_per_img[page.tag]
- top_img = top_img ? top_img : (theme.tag_img !== false ? theme.tag_img || theme.default_top_img : false)
else if is_category()
- var top_img = theme.category_per_img && theme.category_per_img[page.category]
- top_img = top_img ? top_img : (theme.category_img !== false ? theme.category_img || theme.default_top_img : false)
else if is_home()
- var top_img = theme.index_img !== false ? theme.index_img || theme.default_top_img : false
else if is_archive()
- var top_img = theme.archive_img !== false ? theme.archive_img || theme.default_top_img : false
else
- var top_img = page.top_img || theme.default_top_img
if top_img !== false
- var imgSource = top_img && top_img.indexOf('/') !== -1 ? `background-image: url('${url_for(top_img)}')` : `background: ${top_img}`
- var bg_img = top_img ? imgSource : ''
- var site_title = page.title || page.tag || page.category || config.title
- var isHomeClass = is_home() ? 'full_page' : 'not-home-page'
- is_post() ? isHomeClass = 'post-bg' : isHomeClass
else
- var isHomeClass = 'not-top-img'
else
- var top_img = false
- var isHomeClass = 'not-top-img'
header#page-header(class=isHomeClass style=bg_img)
!=partial('includes/header/nav', {}, {cache: true})
if top_img !== false
if is_post()
include ./post-info.pug
else if is_home()
#site-info
h1#site-title=site_title
if theme.subtitle.enable
- var loadSubJs = true
#site-subtitle
span#subtitle
if(theme.social)
#site_social_icons
!=fragment_cache('social', function(){return partial('includes/header/social')})
#scroll-down
i.fas.fa-angle-down.scroll-down-effects
else
#page-site-info
h1#site-title=site_title

View File

@ -0,0 +1,27 @@
if theme.menu
.menus_items
each value, label in theme.menu
if typeof value !== 'object'
.menus_item
- const valueArray = value.split('||')
a.site-page(href=url_for(trim(valueArray[0])))
if valueArray[1]
i.fa-fw(class=trim(valueArray[1]))
span=' '+label
else
.menus_item
- const labelArray = label.split('||')
- const hideClass = labelArray[2] && trim(labelArray[2]) === 'hide' ? 'hide' : ''
a.site-page.group(class=`${hideClass}` href='javascript:void(0);')
if labelArray[1]
i.fa-fw(class=trim(labelArray[1]))
span=' '+ trim(labelArray[0])
i.fas.fa-chevron-down
ul.menus_item_child
each val,lab in value
- const valArray = val.split('||')
li
a.site-page.child(href=url_for(trim(valArray[0])))
if valArray[1]
i.fa-fw(class=trim(valArray[1]))
span=' '+ lab

View File

@ -0,0 +1,17 @@
nav#nav
span#blog_name
a#site-name(href=url_for('/')) #[=config.title]
#menus
if (theme.algolia_search.enable || theme.local_search.enable)
#search-button
a.site-page.social-icon.search
i.fas.fa-search.fa-fw
span=' '+_p('search.title')
!=partial('includes/header/menu_item', {}, {cache: true})
#toggle-menu
a.site-page
i.fas.fa-bars.fa-fw

View File

@ -0,0 +1,138 @@
- let comments = theme.comments
#post-info
h1.post-title= page.title || _p('no_title')
if theme.post_edit.enable
a.post-edit-link(href=theme.post_edit.url + page.source title=_p('post.edit') target="_blank")
i.fas.fa-pencil-alt
#post-meta
.meta-firstline
if (theme.post_meta.post.date_type)
span.post-meta-date
if (theme.post_meta.post.date_type === 'both')
i.far.fa-calendar-alt.fa-fw.post-meta-icon
span.post-meta-label= _p('post.created')
time.post-meta-date-created(datetime=date_xml(page.date) title=_p('post.created') + ' ' + full_date(page.date))=date(page.date, config.date_format)
span.post-meta-separator |
i.fas.fa-history.fa-fw.post-meta-icon
span.post-meta-label= _p('post.updated')
time.post-meta-date-updated(datetime=date_xml(page.updated) title=_p('post.updated') + ' ' + full_date(page.updated))=date(page.updated, config.date_format)
else
- let data_type_update = theme.post_meta.post.date_type === 'updated'
- let date_type = data_type_update ? 'updated' : 'date'
- let date_icon = data_type_update ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_update ? _p('post.updated') : _p('post.created')
i.fa-fw.post-meta-icon(class=date_icon)
span.post-meta-label= date_title
time(datetime=date_xml(page[date_type]) title=date_title + ' ' + full_date(page[date_type]))=date(page[date_type], config.date_format)
if (theme.post_meta.post.categories && page.categories.data.length > 0)
span.post-meta-categories
if (theme.post_meta.post.date_type)
span.post-meta-separator |
each item, index in page.categories.data
i.fas.fa-inbox.fa-fw.post-meta-icon
a(href=url_for(item.path)).post-meta-categories #[=item.name]
if (index < page.categories.data.length - 1)
i.fas.fa-angle-right.post-meta-separator
.meta-secondline
- let postWordcount = theme.wordcount.enable && (theme.wordcount.post_wordcount || theme.wordcount.min2read)
if (postWordcount)
span.post-meta-separator |
span.post-meta-wordcount
if theme.wordcount.post_wordcount
i.far.fa-file-word.fa-fw.post-meta-icon
span.post-meta-label= _p('post.wordcount') + ':'
span.word-count= wordcount(page.content)
if theme.wordcount.min2read
span.post-meta-separator |
if theme.wordcount.min2read
i.far.fa-clock.fa-fw.post-meta-icon
span.post-meta-label= _p('post.min2read') + ':'
span= min2read(page.content, {cn: 350, en: 160}) + _p('post.min2read_unit')
//- for pv and count
mixin pvBlock(parent_id,parent_class,parent_title)
span.post-meta-separator |
span(class=parent_class id=parent_id data-flag-title=page.title)
i.far.fa-eye.fa-fw.post-meta-icon
span.post-meta-label=_p('post.page_pv') + ':'
if block
block
- const commentUse = comments.use
if page.comments !== false && commentUse && !comments.lazyload
if commentUse[0] === 'Valine' && theme.valine.visitor
+pvBlock(url_for(page.path),'leancloud_visitors',page.title)
span.leancloud-visitors-count
i.fa-solid.fa-spinner.fa-spin
else if commentUse[0] === 'Waline' && theme.waline.pageview
+pvBlock('','','')
span.waline-pageview-count(data-path=url_for(page.path))
i.fa-solid.fa-spinner.fa-spin
else if commentUse[0] === 'Twikoo' && theme.twikoo.visitor
+pvBlock('','','')
span#twikoo_visitors
i.fa-solid.fa-spinner.fa-spin
else if theme.busuanzi.page_pv
+pvBlock('','post-meta-pv-cv','')
span#busuanzi_value_page_pv
i.fa-solid.fa-spinner.fa-spin
else if theme.busuanzi.page_pv
+pvBlock('','post-meta-pv-cv','')
span#busuanzi_value_page_pv
i.fa-solid.fa-spinner.fa-spin
if comments.count && !comments.lazyload && page.comments !== false && comments.use
- var whichCount = comments.use[0]
mixin countBlock
span.post-meta-separator |
span.post-meta-commentcount
i.far.fa-comments.fa-fw.post-meta-icon
span.post-meta-label= _p('post.comments') + ':'
if block
block
case whichCount
when 'Disqus'
+countBlock
span.disqus-comment-count
a(href=full_url_for(page.path) + '#disqus_thread')
i.fa-solid.fa-spinner.fa-spin
when 'Disqusjs'
+countBlock
a(href=full_url_for(page.path) + '#disqusjs')
span.disqus-comment-count(data-disqus-url=full_url_for(page.path))
i.fa-solid.fa-spinner.fa-spin
when 'Valine'
+countBlock
a(href=url_for(page.path) + '#post-comment' itemprop="discussionUrl")
span.valine-comment-count(data-xid=url_for(page.path) itemprop="commentCount")
i.fa-solid.fa-spinner.fa-spin
when 'Waline'
+countBlock
a(href=url_for(page.path) + '#post-comment')
span.waline-comment-count(data-path=url_for(page.path))
i.fa-solid.fa-spinner.fa-spin
when 'Gitalk'
+countBlock
a(href=url_for(page.path) + '#post-comment')
span.gitalk-comment-count
i.fa-solid.fa-spinner.fa-spin
when 'Twikoo'
+countBlock
a(href=url_for(page.path) + '#post-comment')
span#twikoo-count
i.fa-solid.fa-spinner.fa-spin
when 'Facebook Comments'
+countBlock
a(href=url_for(page.path) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex())
i.fa-solid.fa-spinner.fa-spin
when 'Remark42'
+countBlock
a(href=url_for(page.path) + '#post-comment')
span.remark42__counter(data-url=urlNoIndex())
i.fa-solid.fa-spinner.fa-spin

View File

@ -0,0 +1,4 @@
each url, icon in theme.social
a.social-icon(href=url_for(trim(url.split('||')[0])) target="_blank"
title=url.split('||')[1] === undefined ? '' : trim(url.split('||')[1]))
i(class=icon)

View File

@ -0,0 +1,48 @@
- var htmlClassHideAside = theme.aside.enable && theme.aside.hide ? 'hide-aside' : ''
- page.aside = is_archive() ? theme.aside.display.archive: is_category() ? theme.aside.display.category : is_tag() ? theme.aside.display.tag : page.aside
- var hideAside = !theme.aside.enable || page.aside === false ? 'hide-aside' : ''
- var pageType = is_post() ? 'post' : 'page'
doctype html
html(lang=config.language data-theme=theme.display_mode class=htmlClassHideAside)
head
include ./head.pug
body
if theme.preloader
!=partial('includes/loading/loading', {}, {cache: true})
if theme.background
#web_bg
!=partial('includes/sidebar', {}, {cache: true})
if page.type !== '404'
#body-wrap(class=pageType)
include ./header/index.pug
main#content-inner.layout(class=hideAside)
if body
div!= body
else
block content
if theme.aside.enable && page.aside !== false
include widget/index.pug
- var footerBg = theme.footer_bg
if (footerBg)
if (footerBg === true)
- var footer_bg = bg_img
else
- var footer_bg = theme.footer_bg.indexOf('/') !== -1 ? `background-image: url('${url_for(footerBg)}')` : `background: ${footerBg}`
else
- var footer_bg = ''
footer#footer(style=footer_bg)
!=partial('includes/footer', {}, {cache: true})
else
include ./404.pug
include ./rightside.pug
!=partial('includes/third-party/search/index', {}, {cache: true})
include ./additional-js.pug

View File

@ -0,0 +1,13 @@
script.
var preloader = {
endLoading: () => {
document.body.style.overflow = 'auto';
document.getElementById('loading-box').classList.add("loaded")
},
initLoading: () => {
document.body.style.overflow = '';
document.getElementById('loading-box').classList.remove("loaded")
}
}
window.addEventListener('load',preloader.endLoading())

View File

@ -0,0 +1,9 @@
#loading-box
.loading-left-bg
.loading-right-bg
.spinner-box
.configure-border-1
.configure-core
.configure-border-2
.configure-core
.loading-word= _p('loading')

View File

@ -0,0 +1,20 @@
mixin articleSort(posts)
.article-sort
- var year
- posts.each(function (article) {
- let tempYear = date(article.date, 'YYYY')
- let no_cover = article.cover === false || !theme.cover.archives_enable ? 'no-article-cover' : ''
- let title = article.title || _p('no_title')
if tempYear !== year
- year = tempYear
.article-sort-item.year= year
.article-sort-item(class=no_cover)
if article.cover && theme.cover.archives_enable
a.article-sort-item-img(href=url_for(article.path) title=title)
img(src=url_for(article.cover) alt=title onerror=`this.onerror=null;this.src='${url_for(theme.error_img.post_page)}'`)
.article-sort-item-info
.article-sort-item-time
i.far.fa-calendar-alt
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))= date(article.date, config.date_format)
a.article-sort-item-title(href=url_for(article.path) title=title)= title
- })

View File

@ -0,0 +1,128 @@
mixin postUI(posts)
each article , index in page.posts.data
.recent-post-item
-
let link = article.link || article.path
let title = article.title || _p('no_title')
const position = theme.cover.position
let leftOrRight = position === 'both'
? index%2 == 0 ? 'left' : 'right'
: position === 'left' ? 'left' : 'right'
let post_cover = article.cover
let no_cover = article.cover === false || !theme.cover.index_enable ? 'no-cover' : ''
-
if post_cover && theme.cover.index_enable
.post_cover(class=leftOrRight)
a(href=url_for(link) title=title)
img.post_bg(src=url_for(post_cover) onerror=`this.onerror=null;this.src='`+ url_for(theme.error_img.post_page) + `'` alt=title)
.recent-post-info(class=no_cover)
a.article-title(href=url_for(link) title=title)= title
.article-meta-wrap
if (is_home() && (article.top || article.sticky > 0))
span.article-meta
i.fas.fa-thumbtack.sticky
span.sticky= _p('sticky')
span.article-meta-separator |
if (theme.post_meta.page.date_type)
span.post-meta-date
if (theme.post_meta.page.date_type === 'both')
i.far.fa-calendar-alt
span.article-meta-label=_p('post.created')
time.post-meta-date-created(datetime=date_xml(article.date) title=_p('post.created') + ' ' + full_date(article.date))=date(article.date, config.date_format)
span.article-meta-separator |
i.fas.fa-history
span.article-meta-label=_p('post.updated')
time.post-meta-date-updated(datetime=date_xml(article.updated) title=_p('post.updated') + ' ' + full_date(article.updated))=date(article.updated, config.date_format)
else
- let data_type_updated = theme.post_meta.page.date_type === 'updated'
- let date_type = data_type_updated ? 'updated' : 'date'
- let date_icon = data_type_updated ? 'fas fa-history' :'far fa-calendar-alt'
- let date_title = data_type_updated ? _p('post.updated') : _p('post.created')
i(class=date_icon)
span.article-meta-label=date_title
time(datetime=date_xml(article[date_type]) title=date_title + ' ' + full_date(article[date_type]))=date(article[date_type], config.date_format)
if (theme.post_meta.page.categories && article.categories.data.length > 0)
span.article-meta
span.article-meta-separator |
i.fas.fa-inbox
each item, index in article.categories.data
a(href=url_for(item.path)).article-meta__categories #[=item.name]
if (index < article.categories.data.length - 1)
i.fas.fa-angle-right.article-meta-link
if (theme.post_meta.page.tags && article.tags.data.length > 0)
span.article-meta.tags
span.article-meta-separator |
i.fas.fa-tag
each item, index in article.tags.data
a(href=url_for(item.path)).article-meta__tags #[=item.name]
if (index < article.tags.data.length - 1)
span.article-meta-link #[='•']
mixin countBlockInIndex
- needLoadCountJs = true
span.article-meta
span.article-meta-separator |
i.fas.fa-comments
if block
block
span.article-meta-label= ' ' + _p('card_post_count')
if theme.comments.card_post_count
case theme.comments.use[0]
when 'Disqus'
+countBlockInIndex
a(href=full_url_for(link) + '#disqus_thread')
i.fa-solid.fa-spinner.fa-spin
when 'Disqusjs'
+countBlockInIndex
a(href=full_url_for(link) + '#disqusjs')
span.disqus-comment-count(data-disqus-url=full_url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Valine'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.valine-comment-count(data-xid=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Waline'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.waline-comment-count(id=url_for(link))
i.fa-solid.fa-spinner.fa-spin
when 'Twikoo'
+countBlockInIndex
a.twikoo-count(href=url_for(link) + '#post-comment')
i.fa-solid.fa-spinner.fa-spin
when 'Facebook Comments'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.fb-comments-count(data-href=urlNoIndex(article.permalink))
i.fa-solid.fa-spinner.fa-spin
when 'Remark42'
+countBlockInIndex
a(href=url_for(link) + '#post-comment')
span.remark42__counter(data-url=urlNoIndex(article.permalink))
i.fa-solid.fa-spinner.fa-spin
//- Display the article introduction on homepage
case theme.index_post_content.method
when false
- break
when 1
.content!= article.description
when 2
if article.description
.content!= article.description
else
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
default
- const content = strip_html(article.content)
- let expert = content.substring(0, theme.index_post_content.length)
- content.length > theme.index_post_content.length ? expert += ' ...' : ''
.content!= expert
if theme.ad && theme.ad.index
if (index + 1) % 3 == 0
.recent-post-item.ads-wrap!=theme.ad.index

View File

@ -0,0 +1 @@
.category-lists!= list_categories()

View File

@ -0,0 +1,2 @@
#article-container
!= page.content

View File

@ -0,0 +1,68 @@
#article-container
.flink
if page.flink_url
script.
(()=>{
const replaceSymbol = (str) => {
return str.replace(/[\p{P}\p{S}]/gu, "-")
}
let result = ""
fetch("!{url_for(page.flink_url)}")
.then(response => response.json())
.then(str => {
for(let i = 0; i < str.length; i++){
const replaceClassName = replaceSymbol(str[i].class_name)
const className = str[i].class_name ? `<h2 id="${replaceClassName}"><a href="#${replaceClassName}" class="headerlink" title="${str[i].class_name}"></a>${str[i].class_name}</h2>` : ""
const classDesc = str[i].class_desc ? `<div class="flink-desc">${str[i].class_desc}</div>` : ""
let listResult = ""
const lists = str[i].link_list
for(let j = 0; j < lists.length; j++){
listResult += `
<div class="flink-list-item">
<a href="${lists[j].link}" title="${lists[j].name}" target="_blank">
<div class="flink-item-icon">
<img class="no-lightbox" src="${lists[j].avatar}" onerror='this.onerror=null;this.src="!{url_for(theme.error_img.flink)}"' alt="${lists[j].name}" />
</div>
<div class="flink-item-name">${lists[j].name}</div>
<div class="flink-item-desc" title="${lists[j].descr}">${lists[j].descr}</div>
</a>
</div>`
}
result += `${className}${classDesc} <div class="flink-list">${listResult}</div>`
}
document.querySelector(".flink").insertAdjacentHTML("afterbegin", result)
})
})()
else
if site.data.link
- let result = ""
each i in site.data.link
- let className = i.class_name ? markdown(`## ${i.class_name}`) : ""
- let classDesc = i.class_desc ? `<div class="flink-desc">${i.class_desc}</div>` : ""
- let listResult = ""
each j in i.link_list
-
listResult += `
<div class="flink-list-item">
<a href="${j.link}" title="${j.name}" target="_blank">
<div class="flink-item-icon">
<img class="no-lightbox" src="${j.avatar}" onerror='this.onerror=null;this.src="${url_for(theme.error_img.flink)}"' alt="${j.name}" />
</div>
<div class="flink-item-name">${j.name}</div>
<div class="flink-item-desc" title="${j.descr}">${j.descr}</div>
</a>
</div>`
-
- result += `${className}${classDesc} <div class="flink-list">${listResult}</div>`
- page.content = result + page.content
!= page.content

View File

@ -0,0 +1,2 @@
.tag-cloud-list.is-center
!=cloudTags({source: site.tags, minfontsize: 1.2, maxfontsize: 2.1, limit: 0, unit: 'em'})

View File

@ -0,0 +1,37 @@
-
var options = {
prev_text: '<i class="fas fa-chevron-left fa-fw"></i>',
next_text: '<i class="fas fa-chevron-right fa-fw"></i>',
mid_size: 1,
escape: false
}
if is_post()
- let prev = theme.post_pagination === 1 ? page.prev : page.next
- let next = theme.post_pagination === 1 ? page.next : page.prev
nav#pagination.pagination-post
if(prev)
- var hasPageNext = next ? 'pull-left' : 'pull-full'
.prev-post(class=hasPageNext)
- var pagination_cover = prev.cover === false ? prev.randomcover : prev.cover
a(href=url_for(prev.path))
img.prev-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of previous post')
.pagination-info
.label=_p('pagination.prev')
.prev_info=prev.title
if(next)
- var hasPagePrev = prev ? 'pull-right' : 'pull-full'
- var pagination_cover = next.cover == false ? next.randomcover : next.cover
.next-post(class=hasPagePrev)
a(href=url_for(next.path))
img.next-cover(src=url_for(pagination_cover) onerror=`onerror=null;src='${url_for(theme.error_img.post_page)}'` alt='cover of next post')
.pagination-info
.label=_p('pagination.next')
.next_info=next.title
else
nav#pagination
.pagination
if is_home()
- options.format = 'page/%d/#content-inner'
!=paginator(options)

View File

@ -0,0 +1,17 @@
if theme.post_copyright.enable && page.copyright !== false
- let author = page.copyright_author || config.author
- let authorHref = page.copyright_author_href || theme.post_copyright.author_href || config.url
- let url = page.copyright_url || page.permalink
- let info = page.copyright_info || _p('post.copyright.copyright_content', theme.post_copyright.license_url, theme.post_copyright.license, config.url, config.title)
.post-copyright
.post-copyright__author
span.post-copyright-meta= _p('post.copyright.author') + ": "
span.post-copyright-info
a(href=authorHref)=author
.post-copyright__type
span.post-copyright-meta= _p('post.copyright.link') + ": "
span.post-copyright-info
a(href=url_for(url))= theme.post_copyright.decode ? decodeURI(url) : url
.post-copyright__notice
span.post-copyright-meta= _p('post.copyright.copyright_notice') + ": "
span.post-copyright-info!= info

View File

@ -0,0 +1,13 @@
.post-reward
.reward-button
i.fas.fa-qrcode
= ' ' + _p('donate')
.reward-main
ul.reward-all
each item in theme.reward.QR_code
- var clickTo = item.link ? item.link : item.img
li.reward-item
a(href=url_for(clickTo) target='_blank')
img.post-qr-code-img(src=url_for(item.img) alt=item.text)
.post-qr-code-desc=item.text

View File

@ -0,0 +1,60 @@
- const { readmode, translate, darkmode, aside, chat_btn } = theme
mixin rightsideItem(array)
each item in array
case item
when 'readmode'
if is_post() && readmode
button#readmode(type="button" title=_p('rightside.readmode_title'))
i.fas.fa-book-open
when 'translate'
if translate.enable
button#translateLink(type="button" title=_p('rightside.translate_title'))= translate.default
when 'darkmode'
if darkmode.enable && darkmode.button
button#darkmode(type="button" title=_p('rightside.night_mode_title'))
i.fas.fa-adjust
when 'hideAside'
if aside.enable && aside.button && page.aside !== false
button#hide-aside-btn(type="button" title=_p('rightside.aside'))
i.fas.fa-arrows-alt-h
when 'toc'
if showToc
button#mobile-toc-button.close(type="button" title=_p("rightside.toc"))
i.fas.fa-list-ul
when 'chat'
if chat_btn
button#chat_btn(type="button" title=_p("rightside.chat"))
i.fas.fa-sms
when 'comment'
if commentsJsLoad
a#to_comment(href="#post-comment" title=_p("rightside.scroll_to_comment"))
i.fas.fa-comments
#rightside
- const { enable, hide, show } = theme.rightside_item_order
- const hideArray = enable ? hide && hide.split(',') : ['readmode','translate','darkmode','hideAside']
- const showArray = enable ? show && show.split(',') : ['toc','chat','comment']
#rightside-config-hide
if hideArray
+rightsideItem(hideArray)
#rightside-config-show
if enable
if hide
button#rightside_config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
else
if is_post()
if (readmode || translate.enable || (darkmode.enable && darkmode.button))
button#rightside_config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
else if translate.enable || (darkmode.enable && darkmode.button)
button#rightside_config(type="button" title=_p("rightside.setting"))
i.fas.fa-cog.fa-spin
if showArray
+rightsideItem(showArray)
button#go-up(type="button" title=_p("rightside.back_to_top"))
i.fas.fa-arrow-up

View File

@ -0,0 +1,18 @@
#sidebar
#menu-mask
#sidebar-menus
.avatar-img.is-center
img(src=url_for(theme.avatar.img) onerror=`onerror=null;src='${theme.error_img.flink}'` alt="avatar")
.sidebar-site-data.site-data.is-center
a(href=url_for(config.archive_dir) + '/')
.headline= _p('aside.articles')
.length-num= site.posts.length
a(href=url_for(config.tag_dir) + '/' )
.headline= _p('aside.tags')
.length-num= site.tags.length
a(href=url_for(config.category_dir) + '/')
.headline= _p('aside.categories')
.length-num= site.categories.length
hr
!=partial('includes/header/menu_item', {}, {cache: true})

View File

@ -0,0 +1,3 @@
link(rel='stylesheet' href=url_for(theme.asset.aplayer_css) media="print" onload="this.media='all'")
script(src=url_for(theme.asset.aplayer_js))
script(src=url_for(theme.asset.meting_js))

View File

@ -0,0 +1,16 @@
script.
(() => {
const getCount = () => {
if (window.DISQUSWIDGETS === undefined) {
var d = document, s = d.createElement('script');
s.src = 'https://!{theme.disqus.shortname}.disqus.com/count.js';
s.id = 'dsq-count-scr';
(d.head || d.body).appendChild(s);
} else {
DISQUSWIDGETS.getCount({reset: true});
}
}
window.pjax ? getCount() : window.addEventListener('load', getCount)
})()

View File

@ -0,0 +1,15 @@
script.
(()=>{
function loadFBComment () {
if (typeof FB === 'object') FB.XFBML.parse()
else {
let ele = document.createElement('script')
ele.setAttribute('src','https://connect.facebook.net/!{theme.facebook_comments.lang}/sdk.js#xfbml=1&version=v9.0')
ele.setAttribute('async', 'true')
ele.setAttribute('defer', 'true')
ele.setAttribute('crossorigin', 'anonymous')
document.body.appendChild(ele)
}
}
window.pjax ? loadFBComment() : window.addEventListener('load', loadFBComment)
})()

View File

@ -0,0 +1,14 @@
case theme.comments.use[0]
when 'Twikoo'
include ./twikoo.pug
when 'Disqus'
when 'Disqusjs'
include ./disqus.pug
when 'Valine'
include ./valine.pug
when 'Waline'
include ./waline.pug
when 'Facebook Comments'
include ./fb.pug
when 'Remark42'
include ./remark42.pug

View File

@ -0,0 +1,18 @@
- const { host, siteId, option } = theme.remark42
script.
(()=>{
window.remark_config = Object.assign({
host: '!{host}',
site_id: '!{siteId}',
},!{JSON.stringify(option)})
function getCount () {
const s = document.createElement('script')
s.src = remark_config.host + '/web/counter.js'
s.defer = true
document.head.appendChild(s)
}
window.pjax ? getCount() : window.addEventListener('load', getCount)
})()

Some files were not shown because too many files have changed in this diff Show More